diff --git a/lib/db/db_version_migration.dart b/lib/db/db_version_migration.dart index eb75bf5b1..3cc9b9c3c 100644 --- a/lib/db/db_version_migration.dart +++ b/lib/db/db_version_migration.dart @@ -26,13 +26,14 @@ import 'package:stackwallet/models/node_model.dart'; import 'package:stackwallet/services/mixins/wallet_db.dart'; import 'package:stackwallet/services/node_service.dart'; import 'package:stackwallet/services/wallets_service.dart'; +import 'package:stackwallet/supported_coins.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/default_nodes.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/prefs.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/bitcoincash.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/epiccash.dart'; import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:tuple/tuple.dart'; @@ -59,14 +60,16 @@ class DbVersionMigrator with WalletDB { ElectrumXClient? client; int? latestSetId; + final firo = Firo(CryptoCurrencyNetwork.main); // only instantiate client if there are firo wallets - if (walletInfoList.values.any((element) => element.coin == Coin.firo)) { + if (walletInfoList.values + .any((element) => element.coinIdentifier == firo.identifier)) { await Hive.openBox<NodeModel>(DB.boxNameNodeModels); await Hive.openBox<NodeModel>(DB.boxNamePrimaryNodes); - final node = nodeService.getPrimaryNodeFor(coin: Coin.firo) ?? - DefaultNodes.firo; - List<ElectrumXNode> failovers = nodeService - .failoverNodesFor(coin: Coin.firo) + final node = + nodeService.getPrimaryNodeFor(currency: firo) ?? firo.defaultNode; + final List<ElectrumXNode> failovers = nodeService + .failoverNodesFor(currency: firo) .map( (e) => ElectrumXNode( address: e.host, @@ -80,11 +83,12 @@ class DbVersionMigrator with WalletDB { client = ElectrumXClient.from( node: ElectrumXNode( - address: node.host, - port: node.port, - name: node.name, - id: node.id, - useSSL: node.useSSL), + address: node.host, + port: node.port, + name: node.name, + id: node.id, + useSSL: node.useSSL, + ), prefs: prefs, failovers: failovers, cryptoCurrency: Firo(CryptoCurrencyNetwork.main), @@ -96,26 +100,29 @@ class DbVersionMigrator with WalletDB { // default to 2 for now latestSetId = 2; Logging.instance.log( - "Failed to fetch latest coin id during firo db migrate: $e \nUsing a default value of 2", - level: LogLevel.Warning); + "Failed to fetch latest coin id during firo db migrate: $e \nUsing a default value of 2", + level: LogLevel.Warning, + ); } } for (final walletInfo in walletInfoList.values) { // migrate each firo wallet's lelantus coins - if (walletInfo.coin == Coin.firo) { + if (walletInfo.coinIdentifier == firo.identifier) { await Hive.openBox<dynamic>(walletInfo.walletId); final _lelantusCoins = DB.instance.get<dynamic>( - boxName: walletInfo.walletId, key: '_lelantus_coins') as List?; + boxName: walletInfo.walletId, + key: '_lelantus_coins', + ) as List?; final List<Map<dynamic, LelantusCoin>> lelantusCoins = []; - for (var lCoin in _lelantusCoins ?? []) { + for (final lCoin in _lelantusCoins ?? []) { lelantusCoins .add({lCoin.keys.first: lCoin.values.first as LelantusCoin}); } - List<Map<dynamic, LelantusCoin>> coins = []; + final List<Map<dynamic, LelantusCoin>> coins = []; for (final element in lelantusCoins) { - LelantusCoin coin = element.values.first; + final LelantusCoin coin = element.values.first; int anonSetId = coin.anonymitySetId; if (coin.anonymitySetId == 1 && (coin.publicCoin == '' || @@ -123,21 +130,31 @@ class DbVersionMigrator with WalletDB { anonSetId = latestSetId!; } coins.add({ - element.keys.first: LelantusCoin(coin.index, coin.value, - coin.publicCoin, coin.txId, anonSetId, coin.isUsed) + element.keys.first: LelantusCoin( + coin.index, + coin.value, + coin.publicCoin, + coin.txId, + anonSetId, + coin.isUsed, + ), }); } Logger.print("newcoins $coins", normalLength: false); await DB.instance.put<dynamic>( - boxName: walletInfo.walletId, - key: '_lelantus_coins', - value: coins); + boxName: walletInfo.walletId, + key: '_lelantus_coins', + value: coins, + ); } } // update version await DB.instance.put<dynamic>( - boxName: DB.boxNameDBInfo, key: "hive_data_version", value: 1); + boxName: DB.boxNameDBInfo, + key: "hive_data_version", + value: 1, + ); // try to continue migrating return await migrate(1, secureStore: secureStore); @@ -161,7 +178,10 @@ class DbVersionMigrator with WalletDB { // update version await DB.instance.put<dynamic>( - boxName: DB.boxNameDBInfo, key: "hive_data_version", value: 2); + boxName: DB.boxNameDBInfo, + key: "hive_data_version", + value: 2, + ); // try to continue migrating return await migrate(2, secureStore: secureStore); @@ -176,16 +196,26 @@ class DbVersionMigrator with WalletDB { // update version await DB.instance.put<dynamic>( - boxName: DB.boxNameDBInfo, key: "hive_data_version", value: 3); + boxName: DB.boxNameDBInfo, + key: "hive_data_version", + value: 3, + ); return await migrate(3, secureStore: secureStore); case 3: // clear possible broken firo cache - await DB.instance.clearSharedTransactionCache(coin: Coin.firo); + await DB.instance.clearSharedTransactionCache( + currency: Firo( + CryptoCurrencyNetwork.test, + ), + ); // update version await DB.instance.put<dynamic>( - boxName: DB.boxNameDBInfo, key: "hive_data_version", value: 4); + boxName: DB.boxNameDBInfo, + key: "hive_data_version", + value: 4, + ); // try to continue migrating return await migrate(4, secureStore: secureStore); @@ -196,7 +226,10 @@ class DbVersionMigrator with WalletDB { // update version await DB.instance.put<dynamic>( - boxName: DB.boxNameDBInfo, key: "hive_data_version", value: 5); + boxName: DB.boxNameDBInfo, + key: "hive_data_version", + value: 5, + ); // try to continue migrating return await migrate(5, secureStore: secureStore); @@ -212,11 +245,17 @@ class DbVersionMigrator with WalletDB { "light"; await DB.instance.put<dynamic>( - boxName: DB.boxNamePrefs, key: "theme", value: themeName); + boxName: DB.boxNamePrefs, + key: "theme", + value: themeName, + ); // update version await DB.instance.put<dynamic>( - boxName: DB.boxNameDBInfo, key: "hive_data_version", value: 6); + boxName: DB.boxNameDBInfo, + key: "hive_data_version", + value: 6, + ); // try to continue migrating return await migrate(6, secureStore: secureStore); @@ -287,7 +326,10 @@ class DbVersionMigrator with WalletDB { // update version await DB.instance.put<dynamic>( - boxName: DB.boxNameDBInfo, key: "hive_data_version", value: 7); + boxName: DB.boxNameDBInfo, + key: "hive_data_version", + value: 7, + ); // try to continue migrating return await migrate(7, secureStore: secureStore); @@ -298,7 +340,10 @@ class DbVersionMigrator with WalletDB { // update version await DB.instance.put<dynamic>( - boxName: DB.boxNameDBInfo, key: "hive_data_version", value: 8); + boxName: DB.boxNameDBInfo, + key: "hive_data_version", + value: 8, + ); // try to continue migrating return await migrate(8, secureStore: secureStore); @@ -311,8 +356,10 @@ class DbVersionMigrator with WalletDB { await MainDB.instance.initMainDB(); for (final walletId in walletInfoList.keys) { final info = walletInfoList[walletId]!; - if (info.coin == Coin.bitcoincash || - info.coin == Coin.bitcoincashTestnet) { + if (info.coinIdentifier == + Bitcoincash(CryptoCurrencyNetwork.main).identifier || + info.coinIdentifier == + Bitcoincash(CryptoCurrencyNetwork.test).identifier) { final ids = await MainDB.instance .getAddresses(walletId) .filter() @@ -328,7 +375,10 @@ class DbVersionMigrator with WalletDB { // update version await DB.instance.put<dynamic>( - boxName: DB.boxNameDBInfo, key: "hive_data_version", value: 9); + boxName: DB.boxNameDBInfo, + key: "hive_data_version", + value: 9, + ); // try to continue migrating return await migrate(9, secureStore: secureStore); @@ -339,7 +389,10 @@ class DbVersionMigrator with WalletDB { // update version await DB.instance.put<dynamic>( - boxName: DB.boxNameDBInfo, key: "hive_data_version", value: 10); + boxName: DB.boxNameDBInfo, + key: "hive_data_version", + value: 10, + ); // try to continue migrating return await migrate(10, secureStore: secureStore); @@ -350,7 +403,10 @@ class DbVersionMigrator with WalletDB { // update version await DB.instance.put<dynamic>( - boxName: DB.boxNameDBInfo, key: "hive_data_version", value: 11); + boxName: DB.boxNameDBInfo, + key: "hive_data_version", + value: 11, + ); // try to continue migrating return await migrate(11, secureStore: secureStore); @@ -361,7 +417,10 @@ class DbVersionMigrator with WalletDB { // update version await DB.instance.put<dynamic>( - boxName: DB.boxNameDBInfo, key: "hive_data_version", value: 12); + boxName: DB.boxNameDBInfo, + key: "hive_data_version", + value: 12, + ); // try to continue migrating return await migrate(12, secureStore: secureStore); @@ -392,7 +451,8 @@ class DbVersionMigrator with WalletDB { // we need to manually migrate epic cash transactions as they are not // stored on the epic cash blockchain - if (info.coin == Coin.epicCash) { + final epic = Epiccash(CryptoCurrencyNetwork.main); + if (info.coinIdentifier == epic.identifier) { final txnData = walletBox.get("latest_tx_model") as TransactionData?; // we ever only used index 0 in the past @@ -404,7 +464,7 @@ class DbVersionMigrator with WalletDB { final txns = txnData.getAllTransactions(); for (final tx in txns.values) { - bool isIncoming = tx.txType == "Received"; + final bool isIncoming = tx.txType == "Received"; final iTx = isar_models.Transaction( walletId: walletId, @@ -417,7 +477,7 @@ class DbVersionMigrator with WalletDB { amount: tx.amount, amountString: Amount( rawValue: BigInt.from(tx.amount), - fractionDigits: info.coin.decimals, + fractionDigits: epic.fractionDigits, ).toJsonString(), fee: tx.fees, height: tx.height, @@ -470,12 +530,14 @@ class DbVersionMigrator with WalletDB { if ((await secureStore.read(key: '${walletId}_mnemonicPassphrase')) == null) { await secureStore.write( - key: '${walletId}_mnemonicPassphrase', value: ""); + key: '${walletId}_mnemonicPassphrase', + value: "", + ); } // doing this for epic cash will delete transaction history as it is not // stored on the epic cash blockchain - if (info.coin != Coin.epicCash) { + if (info.coinIdentifier != epic.identifier) { // set flag to initiate full rescan on opening wallet await DB.instance.put<dynamic>( boxName: DB.boxNameDBInfo, @@ -498,6 +560,8 @@ class DbVersionMigrator with WalletDB { final count = await MainDB.instance.getTransactions(walletId).count(); + final crypto = SupportedCoins.getCryptoCurrencyFor(info.coinIdentifier); + for (var i = 0; i < count; i += 50) { final txns = await MainDB.instance .getTransactions(walletId) @@ -512,7 +576,7 @@ class DbVersionMigrator with WalletDB { tx ..amountString = Amount( rawValue: BigInt.from(tx.amount), - fractionDigits: info.coin.decimals, + fractionDigits: crypto.fractionDigits, ).toJsonString(), tx.address.value, ), @@ -531,11 +595,13 @@ class DbVersionMigrator with WalletDB { final keys = List<String>.from(addressBookBox.keys); final contacts = keys - .map((id) => Contact.fromJson( - Map<String, dynamic>.from( - addressBookBox.get(id) as Map, - ), - )) + .map( + (id) => Contact.fromJson( + Map<String, dynamic>.from( + addressBookBox.get(id) as Map, + ), + ), + ) .toList(growable: false); final List<isar_contact.ContactEntry> newContacts = []; @@ -547,7 +613,7 @@ class DbVersionMigrator with WalletDB { for (final entry in contact.addresses) { newContactAddressEntries.add( isar_contact.ContactAddressEntry() - ..coinName = entry.coin.name + ..coinName = entry.coin.identifier ..address = entry.address ..label = entry.label ..other = entry.other, @@ -580,11 +646,13 @@ class DbVersionMigrator with WalletDB { await prefs.init(); await MainDB.instance.initMainDB(); + final firo = Firo(CryptoCurrencyNetwork.main); + for (final walletId in walletInfoList.keys) { final info = walletInfoList[walletId]!; assert(info.walletId == walletId); - if (info.coin == Coin.firo && + if (info.coinIdentifier == firo.identifier && MainDB.instance.isar.lelantusCoins .where() .walletIdEqualTo(walletId) diff --git a/lib/db/hive/db.dart b/lib/db/hive/db.dart index 6f4ebd3c3..f63c00e94 100644 --- a/lib/db/hive/db.dart +++ b/lib/db/hive/db.dart @@ -18,8 +18,10 @@ import 'package:stackwallet/models/node_model.dart'; import 'package:stackwallet/models/notification_model.dart'; import 'package:stackwallet/models/trade_wallet_lookup.dart'; import 'package:stackwallet/services/wallets_service.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/supported_coins.dart'; import 'package:stackwallet/utilities/logger.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; class DB { // legacy (required for migrations) @@ -48,17 +50,18 @@ class DB { static const String boxNamePrefs = "prefs"; static const String boxNameOneTimeDialogsShown = "oneTimeDialogsShown"; - String _boxNameTxCache({required Coin coin}) => "${coin.name}_txCache"; + String _boxNameTxCache({required CryptoCurrency currency}) => + "${currency.identifier}_txCache"; // firo only - String _boxNameSetCache({required Coin coin}) => - "${coin.name}_anonymitySetCache"; - String _boxNameSetSparkCache({required Coin coin}) => - "${coin.name}_anonymitySetSparkCache"; - String _boxNameUsedSerialsCache({required Coin coin}) => - "${coin.name}_usedSerialsCache"; - String _boxNameSparkUsedCoinsTagsCache({required Coin coin}) => - "${coin.name}_sparkUsedCoinsTagsCache"; + String _boxNameSetCache({required CryptoCurrency currency}) => + "${currency.identifier}_anonymitySetCache"; + String _boxNameSetSparkCache({required CryptoCurrency currency}) => + "${currency.identifier}_anonymitySetSparkCache"; + String _boxNameUsedSerialsCache({required CryptoCurrency currency}) => + "${currency.identifier}_usedSerialsCache"; + String _boxNameSparkUsedCoinsTagsCache({required CryptoCurrency currency}) => + "${currency.identifier}_sparkUsedCoinsTagsCache"; Box<NodeModel>? _boxNodeModels; Box<NodeModel>? _boxPrimaryNodes; @@ -77,11 +80,11 @@ class DB { final Map<String, Box<dynamic>> _walletBoxes = {}; - final Map<Coin, Box<dynamic>> _txCacheBoxes = {}; - final Map<Coin, Box<dynamic>> _setCacheBoxes = {}; - final Map<Coin, Box<dynamic>> _setSparkCacheBoxes = {}; - final Map<Coin, Box<dynamic>> _usedSerialsCacheBoxes = {}; - final Map<Coin, Box<dynamic>> _getSparkUsedCoinsTagsCacheBoxes = {}; + final Map<String, Box<dynamic>> _txCacheBoxes = {}; + final Map<String, Box<dynamic>> _setCacheBoxes = {}; + final Map<String, Box<dynamic>> _setSparkCacheBoxes = {}; + final Map<String, Box<dynamic>> _usedSerialsCacheBoxes = {}; + final Map<String, Box<dynamic>> _getSparkUsedCoinsTagsCacheBoxes = {}; // exposed for monero Box<xmr.WalletInfo> get moneroWalletInfoBox => _walletInfoSource!; @@ -97,7 +100,8 @@ class DB { // TODO: make sure this works properly if (Isolate.current.debugName != "main") { throw Exception( - "DB.instance should not be accessed outside the main isolate!"); + "DB.instance should not be accessed outside the main isolate!", + ); } return _instance; @@ -160,17 +164,22 @@ class DB { names.removeWhere((name, dyn) { final jsonObject = Map<String, dynamic>.from(dyn as Map); try { - Coin.values.byName(jsonObject["coin"] as String); + SupportedCoins.getCryptoCurrencyFor(jsonObject["coin"] as String); return false; } catch (e, s) { Logging.instance.log( - "Error, ${jsonObject["coin"]} does not exist, $name wallet cannot be loaded", - level: LogLevel.Error); + "Error, ${jsonObject["coin"]} does not exist, $name wallet cannot be loaded", + level: LogLevel.Error, + ); return true; } }); - final mapped = Map<String, dynamic>.from(names).map((name, dyn) => MapEntry( - name, WalletInfo.fromJson(Map<String, dynamic>.from(dyn as Map)))); + final mapped = Map<String, dynamic>.from(names).map( + (name, dyn) => MapEntry( + name, + WalletInfo.fromJson(Map<String, dynamic>.from(dyn as Map)), + ), + ); for (final entry in mapped.entries) { if (Hive.isBoxOpen(entry.value.walletId)) { @@ -183,70 +192,90 @@ class DB { } } - Future<Box<dynamic>> getTxCacheBox({required Coin coin}) async { - if (_txCacheBoxes[coin]?.isOpen != true) { - _txCacheBoxes.remove(coin); + Future<Box<dynamic>> getTxCacheBox({required CryptoCurrency currency}) async { + if (_txCacheBoxes[currency.identifier]?.isOpen != true) { + _txCacheBoxes.remove(currency.identifier); } - return _txCacheBoxes[coin] ??= - await Hive.openBox<dynamic>(_boxNameTxCache(coin: coin)); + return _txCacheBoxes[currency.identifier] ??= + await Hive.openBox<dynamic>(_boxNameTxCache(currency: currency)); } - Future<void> closeTxCacheBox({required Coin coin}) async { - await _txCacheBoxes[coin]?.close(); + Future<void> closeTxCacheBox({required CryptoCurrency currency}) async { + await _txCacheBoxes[currency.identifier]?.close(); } - Future<Box<dynamic>> getAnonymitySetCacheBox({required Coin coin}) async { - if (_setCacheBoxes[coin]?.isOpen != true) { - _setCacheBoxes.remove(coin); + Future<Box<dynamic>> getAnonymitySetCacheBox({ + required CryptoCurrency currency, + }) async { + if (_setCacheBoxes[currency.identifier]?.isOpen != true) { + _setCacheBoxes.remove(currency.identifier); } - return _setCacheBoxes[coin] ??= - await Hive.openBox<dynamic>(_boxNameSetCache(coin: coin)); + return _setCacheBoxes[currency.identifier] ??= + await Hive.openBox<dynamic>(_boxNameSetCache(currency: currency)); } - Future<Box<dynamic>> getSparkAnonymitySetCacheBox( - {required Coin coin}) async { - if (_setSparkCacheBoxes[coin]?.isOpen != true) { - _setSparkCacheBoxes.remove(coin); + Future<Box<dynamic>> getSparkAnonymitySetCacheBox({ + required CryptoCurrency currency, + }) async { + if (_setSparkCacheBoxes[currency.identifier]?.isOpen != true) { + _setSparkCacheBoxes.remove(currency.identifier); } - return _setSparkCacheBoxes[coin] ??= - await Hive.openBox<dynamic>(_boxNameSetSparkCache(coin: coin)); + return _setSparkCacheBoxes[currency.identifier] ??= + await Hive.openBox<dynamic>(_boxNameSetSparkCache(currency: currency)); } - Future<void> closeAnonymitySetCacheBox({required Coin coin}) async { - await _setCacheBoxes[coin]?.close(); + Future<void> closeAnonymitySetCacheBox({ + required CryptoCurrency currency, + }) async { + await _setCacheBoxes[currency.identifier]?.close(); } - Future<Box<dynamic>> getUsedSerialsCacheBox({required Coin coin}) async { - if (_usedSerialsCacheBoxes[coin]?.isOpen != true) { - _usedSerialsCacheBoxes.remove(coin); + Future<Box<dynamic>> getUsedSerialsCacheBox({ + required CryptoCurrency currency, + }) async { + if (_usedSerialsCacheBoxes[currency.identifier]?.isOpen != true) { + _usedSerialsCacheBoxes.remove(currency.identifier); } - return _usedSerialsCacheBoxes[coin] ??= - await Hive.openBox<dynamic>(_boxNameUsedSerialsCache(coin: coin)); - } - - Future<Box<dynamic>> getSparkUsedCoinsTagsCacheBox( - {required Coin coin}) async { - if (_getSparkUsedCoinsTagsCacheBoxes[coin]?.isOpen != true) { - _getSparkUsedCoinsTagsCacheBoxes.remove(coin); - } - return _getSparkUsedCoinsTagsCacheBoxes[coin] ??= + return _usedSerialsCacheBoxes[currency.identifier] ??= await Hive.openBox<dynamic>( - _boxNameSparkUsedCoinsTagsCache(coin: coin)); + _boxNameUsedSerialsCache(currency: currency), + ); } - Future<void> closeUsedSerialsCacheBox({required Coin coin}) async { - await _usedSerialsCacheBoxes[coin]?.close(); + Future<Box<dynamic>> getSparkUsedCoinsTagsCacheBox({ + required CryptoCurrency currency, + }) async { + if (_getSparkUsedCoinsTagsCacheBoxes[currency.identifier]?.isOpen != true) { + _getSparkUsedCoinsTagsCacheBoxes.remove(currency.identifier); + } + return _getSparkUsedCoinsTagsCacheBoxes[currency.identifier] ??= + await Hive.openBox<dynamic>( + _boxNameSparkUsedCoinsTagsCache(currency: currency), + ); + } + + Future<void> closeUsedSerialsCacheBox({ + required CryptoCurrency currency, + }) async { + await _usedSerialsCacheBoxes[currency.identifier]?.close(); } /// Clear all cached transactions for the specified coin - Future<void> clearSharedTransactionCache({required Coin coin}) async { - await deleteAll<dynamic>(boxName: _boxNameTxCache(coin: coin)); - if (coin == Coin.firo || coin == Coin.firoTestNet) { - await deleteAll<dynamic>(boxName: _boxNameSetCache(coin: coin)); - await deleteAll<dynamic>(boxName: _boxNameSetSparkCache(coin: coin)); - await deleteAll<dynamic>(boxName: _boxNameUsedSerialsCache(coin: coin)); + Future<void> clearSharedTransactionCache({ + required CryptoCurrency currency, + }) async { + await deleteAll<dynamic>(boxName: _boxNameTxCache(currency: currency)); + if (currency is Firo) { + await deleteAll<dynamic>(boxName: _boxNameSetCache(currency: currency)); await deleteAll<dynamic>( - boxName: _boxNameSparkUsedCoinsTagsCache(coin: coin)); + boxName: _boxNameSetSparkCache(currency: currency), + ); + await deleteAll<dynamic>( + boxName: _boxNameUsedSerialsCache(currency: currency), + ); + await deleteAll<dynamic>( + boxName: _boxNameSparkUsedCoinsTagsCache(currency: currency), + ); } } @@ -284,23 +313,28 @@ class DB { // writes - Future<void> put<T>( - {required String boxName, - required dynamic key, - required T value}) async => + Future<void> put<T>({ + required String boxName, + required dynamic key, + required T value, + }) async => await mutex .protect(() async => await Hive.box<T>(boxName).put(key, value)); Future<void> add<T>({required String boxName, required T value}) async => await mutex.protect(() async => await Hive.box<T>(boxName).add(value)); - Future<void> addAll<T>( - {required String boxName, required Iterable<T> values}) async => + Future<void> addAll<T>({ + required String boxName, + required Iterable<T> values, + }) async => await mutex .protect(() async => await Hive.box<T>(boxName).addAll(values)); - Future<void> delete<T>( - {required dynamic key, required String boxName}) async => + Future<void> delete<T>({ + required dynamic key, + required String boxName, + }) async => await mutex.protect(() async => await Hive.box<T>(boxName).delete(key)); Future<void> deleteAll<T>({required String boxName}) async { diff --git a/lib/db/isar/main_db.dart b/lib/db/isar/main_db.dart index ac5a544f4..62673b004 100644 --- a/lib/db/isar/main_db.dart +++ b/lib/db/isar/main_db.dart @@ -19,8 +19,8 @@ import 'package:stackwallet/models/isar/models/isar_models.dart'; import 'package:stackwallet/models/isar/ordinal.dart'; import 'package:stackwallet/models/isar/stack_theme.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/stack_file_system.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/isar/models/frost_wallet_info.dart'; import 'package:stackwallet/wallets/isar/models/spark_coin.dart'; import 'package:stackwallet/wallets/isar/models/token_wallet_info.dart'; @@ -149,15 +149,17 @@ class MainDB { } // tx block explorers - TransactionBlockExplorer? getTransactionBlockExplorer({required Coin coin}) { + TransactionBlockExplorer? getTransactionBlockExplorer( + {required CryptoCurrency cryptoCurrency}) { return isar.transactionBlockExplorers .where() - .tickerEqualTo(coin.ticker) + .tickerEqualTo(cryptoCurrency.ticker) .findFirstSync(); } Future<int> putTransactionBlockExplorer( - TransactionBlockExplorer explorer) async { + TransactionBlockExplorer explorer, + ) async { try { return await isar.writeTxn(() async { return await isar.transactionBlockExplorers.put(explorer); @@ -169,7 +171,8 @@ class MainDB { // addresses QueryBuilder<Address, Address, QAfterWhereClause> getAddresses( - String walletId) => + String walletId, + ) => isar.addresses.where().walletIdEqualTo(walletId); Future<int> putAddress(Address address) async { @@ -194,7 +197,7 @@ class MainDB { Future<List<int>> updateOrPutAddresses(List<Address> addresses) async { try { - List<int> ids = []; + final List<int> ids = []; await isar.writeTxn(() async { for (final address in addresses) { final storedAddress = await isar.addresses @@ -239,13 +242,16 @@ class MainDB { }); } catch (e) { throw MainDBException( - "failed updateAddress: from=$oldAddress to=$newAddress", e); + "failed updateAddress: from=$oldAddress to=$newAddress", + e, + ); } } // transactions QueryBuilder<Transaction, Transaction, QAfterWhereClause> getTransactions( - String walletId) => + String walletId, + ) => isar.transactions.where().walletIdEqualTo(walletId); Future<int> putTransaction(Transaction transaction) async { @@ -284,7 +290,9 @@ class MainDB { isar.utxos.where().walletIdEqualTo(walletId); QueryBuilder<UTXO, UTXO, QAfterFilterCondition> getUTXOsByAddress( - String walletId, String address) => + String walletId, + String address, + ) => isar.utxos .where() .walletIdEqualTo(walletId) @@ -357,7 +365,9 @@ class MainDB { }); Future<TransactionNote?> getTransactionNote( - String walletId, String txid) async { + String walletId, + String txid, + ) async { return isar.transactionNotes.getByTxidWalletId( txid, walletId, @@ -374,7 +384,8 @@ class MainDB { // address labels QueryBuilder<AddressLabel, AddressLabel, QAfterWhereClause> getAddressLabels( - String walletId) => + String walletId, + ) => isar.addressLabels.where().walletIdEqualTo(walletId); Future<int> putAddressLabel(AddressLabel addressLabel) => @@ -392,7 +403,9 @@ class MainDB { }); Future<AddressLabel?> getAddressLabel( - String walletId, String addressString) async { + String walletId, + String addressString, + ) async { return isar.addressLabels.getByAddressStringWalletId( addressString, walletId, @@ -573,7 +586,7 @@ class MainDB { List<TransactionV2> transactions, ) async { try { - List<int> ids = []; + final List<int> ids = []; await isar.writeTxn(() async { for (final tx in transactions) { final storedTx = await isar.transactionV2s @@ -595,7 +608,9 @@ class MainDB { return ids; } catch (e) { throw MainDBException( - "failed updateOrPutTransactionV2s: $transactions", e); + "failed updateOrPutTransactionV2s: $transactions", + e, + ); } } diff --git a/lib/db/migrate_wallets_to_isar.dart b/lib/db/migrate_wallets_to_isar.dart index ab263a1c2..72a9b501f 100644 --- a/lib/db/migrate_wallets_to_isar.dart +++ b/lib/db/migrate_wallets_to_isar.dart @@ -6,8 +6,13 @@ import 'package:stackwallet/db/hive/db.dart'; import 'package:stackwallet/db/isar/main_db.dart'; import 'package:stackwallet/models/isar/models/blockchain_data/v2/transaction_v2.dart'; import 'package:stackwallet/models/isar/models/isar_models.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/supported_coins.dart'; import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/epiccash.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/stellar.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/tezos.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/isar/models/token_wallet_info.dart'; import 'package:stackwallet/wallets/isar/models/wallet_info.dart'; import 'package:stackwallet/wallets/isar/models/wallet_info_meta.dart'; @@ -37,13 +42,13 @@ Future<void> migrateWalletsToIsar({ // final List< ({ - Coin coin, + String coinIdentifier, String name, String walletId, })> oldInfo = Map<String, dynamic>.from(names).values.map((e) { final map = e as Map; return ( - coin: Coin.values.byName(map["coin"] as String), + coinIdentifier: map["coin"] as String, walletId: map["id"] as String, name: map["name"] as String, ); @@ -93,16 +98,16 @@ Future<void> migrateWalletsToIsar({ } // reset stellar + tezos address type - if (old.coin == Coin.stellar || - old.coin == Coin.stellarTestnet || - old.coin == Coin.tezos) { + if (old.coinIdentifier == Stellar(CryptoCurrencyNetwork.main).identifier || + old.coinIdentifier == Stellar(CryptoCurrencyNetwork.test).identifier || + old.coinIdentifier == Tezos(CryptoCurrencyNetwork.main).identifier) { await MainDB.instance.deleteWalletBlockchainData(old.walletId); } // // Set other data values // - Map<String, dynamic> otherData = {}; + final Map<String, dynamic> otherData = {}; final List<String>? tokenContractAddresses = walletBox.get( "ethTokenContracts", @@ -129,7 +134,7 @@ Future<void> migrateWalletsToIsar({ } // epiccash specifics - if (old.coin == Coin.epicCash) { + if (old.coinIdentifier == Epiccash(CryptoCurrencyNetwork.main)) { final epicWalletInfo = ExtraEpiccashWalletInfo.fromMap({ "receivingIndex": walletBox.get("receivingIndex") as int? ?? 0, "changeIndex": walletBox.get("changeIndex") as int? ?? 0, @@ -142,7 +147,9 @@ Future<void> migrateWalletsToIsar({ otherData[WalletInfoKeys.epiccashData] = jsonEncode( epicWalletInfo.toMap(), ); - } else if (old.coin == Coin.firo || old.coin == Coin.firoTestNet) { + } else if (old.coinIdentifier == + Firo(CryptoCurrencyNetwork.main).identifier || + old.coinIdentifier == Firo(CryptoCurrencyNetwork.test).identifier) { otherData[WalletInfoKeys.lelantusCoinIsarRescanRequired] = walletBox .get(WalletInfoKeys.lelantusCoinIsarRescanRequired) as bool? ?? true; @@ -161,10 +168,11 @@ Future<void> migrateWalletsToIsar({ ); final info = WalletInfo( - coinName: old.coin.name, + coinName: old.coinIdentifier, walletId: old.walletId, name: old.name, - mainAddressType: old.coin.primaryAddressType, + mainAddressType: SupportedCoins.getCryptoCurrencyFor(old.coinIdentifier) + .primaryAddressType, favouriteOrderIndex: favourites.indexOf(old.walletId), cachedChainHeight: walletBox.get( DBKeys.storedChainHeight, diff --git a/lib/db/queries/queries.dart b/lib/db/queries/queries.dart index 7e14de0e6..d2b49cea8 100644 --- a/lib/db/queries/queries.dart +++ b/lib/db/queries/queries.dart @@ -42,7 +42,7 @@ extension MainDBQueries on MainDB { required CCFilter filter, required CCSortDescriptor sort, required String searchTerm, - required Coin coin, + required CryptoCurrency cryptoCurrency, }) { var preSort = getUTXOs(walletId).filter().group((q) { final qq = q.group( @@ -79,7 +79,7 @@ extension MainDBQueries on MainDB { qq = qq.or().valueEqualTo( Amount.fromDecimal( maybeDecimal, - fractionDigits: coin.decimals, + fractionDigits: cryptoCurrency.fractionDigits, ).raw.toInt(), ); } @@ -114,7 +114,7 @@ extension MainDBQueries on MainDB { required CCFilter filter, required CCSortDescriptor sort, required String searchTerm, - required Coin coin, + required CryptoCurrency cryptoCurrency, }) { var preSort = getUTXOs(walletId).filter().group((q) { final qq = q.group( @@ -151,7 +151,7 @@ extension MainDBQueries on MainDB { qq = qq.or().valueEqualTo( Amount.fromDecimal( maybeDecimal, - fractionDigits: coin.decimals, + fractionDigits: cryptoCurrency.fractionDigits, ).raw.toInt(), ); } diff --git a/lib/dto/ethereum/eth_token_tx_extra_dto.dart b/lib/dto/ethereum/eth_token_tx_extra_dto.dart index aab41bb76..377b0ad60 100644 --- a/lib/dto/ethereum/eth_token_tx_extra_dto.dart +++ b/lib/dto/ethereum/eth_token_tx_extra_dto.dart @@ -11,7 +11,8 @@ import 'dart:convert'; import 'package:stackwallet/utilities/amount/amount.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/ethereum.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; class EthTokenTxExtraDTO { EthTokenTxExtraDTO({ @@ -42,7 +43,7 @@ class EthTokenTxExtraDTO { to: map['to'] as String, value: Amount( rawValue: BigInt.parse(map['value'] as String), - fractionDigits: Coin.ethereum.decimals, + fractionDigits: Ethereum(CryptoCurrencyNetwork.main).fractionDigits, ), gas: _amountFromJsonNum(map['gas']), gasPrice: _amountFromJsonNum(map['gasPrice']), @@ -70,7 +71,7 @@ class EthTokenTxExtraDTO { static Amount _amountFromJsonNum(dynamic json) { return Amount( rawValue: BigInt.from(json as num), - fractionDigits: Coin.ethereum.decimals, + fractionDigits: Ethereum(CryptoCurrencyNetwork.main).fractionDigits, ); } diff --git a/lib/dto/ethereum/eth_tx_dto.dart b/lib/dto/ethereum/eth_tx_dto.dart index e0708646d..669583170 100644 --- a/lib/dto/ethereum/eth_tx_dto.dart +++ b/lib/dto/ethereum/eth_tx_dto.dart @@ -11,7 +11,8 @@ import 'dart:convert'; import 'package:stackwallet/utilities/amount/amount.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/ethereum.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; class EthTxDTO { EthTxDTO({ @@ -75,7 +76,7 @@ class EthTxDTO { } return Amount( rawValue: BigInt.parse(json.toString()), - fractionDigits: Coin.ethereum.decimals, + fractionDigits: Ethereum(CryptoCurrencyNetwork.main).fractionDigits, ); } diff --git a/lib/electrumx_rpc/cached_electrumx_client.dart b/lib/electrumx_rpc/cached_electrumx_client.dart index 559526f17..10bd0aceb 100644 --- a/lib/electrumx_rpc/cached_electrumx_client.dart +++ b/lib/electrumx_rpc/cached_electrumx_client.dart @@ -13,8 +13,8 @@ import 'dart:math'; import 'package:stackwallet/db/hive/db.dart'; import 'package:stackwallet/electrumx_rpc/electrumx_client.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/logger.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:string_validator/string_validator.dart'; class CachedElectrumXClient { @@ -34,10 +34,11 @@ class CachedElectrumXClient { Future<Map<String, dynamic>> getAnonymitySet({ required String groupId, String blockhash = "", - required Coin coin, + required CryptoCurrency cryptoCurrency, }) async { try { - final box = await DB.instance.getAnonymitySetCacheBox(coin: coin); + final box = + await DB.instance.getAnonymitySetCacheBox(currency: cryptoCurrency); final cachedSet = box.get(groupId) as Map?; Map<String, dynamic> set; @@ -68,30 +69,38 @@ class CachedElectrumXClient { ? base64ToReverseHex(newSet["blockHash"] as String) : newSet["blockHash"]; for (int i = (newSet["coins"] as List).length - 1; i >= 0; i--) { - dynamic newCoin = newSet["coins"][i]; - List<dynamic> translatedCoin = []; - translatedCoin.add(!isHexadecimal(newCoin[0] as String) - ? base64ToHex(newCoin[0] as String) - : newCoin[0]); - translatedCoin.add(!isHexadecimal(newCoin[1] as String) - ? base64ToReverseHex(newCoin[1] as String) - : newCoin[1]); + final dynamic newCoin = newSet["coins"][i]; + final List<dynamic> translatedCoin = []; + translatedCoin.add( + !isHexadecimal(newCoin[0] as String) + ? base64ToHex(newCoin[0] as String) + : newCoin[0], + ); + translatedCoin.add( + !isHexadecimal(newCoin[1] as String) + ? base64ToReverseHex(newCoin[1] as String) + : newCoin[1], + ); try { - translatedCoin.add(!isHexadecimal(newCoin[2] as String) - ? base64ToHex(newCoin[2] as String) - : newCoin[2]); + translatedCoin.add( + !isHexadecimal(newCoin[2] as String) + ? base64ToHex(newCoin[2] as String) + : newCoin[2], + ); } catch (e) { translatedCoin.add(newCoin[2]); } - translatedCoin.add(!isHexadecimal(newCoin[3] as String) - ? base64ToReverseHex(newCoin[3] as String) - : newCoin[3]); + translatedCoin.add( + !isHexadecimal(newCoin[3] as String) + ? base64ToReverseHex(newCoin[3] as String) + : newCoin[3], + ); set["coins"].insert(0, translatedCoin); } // save set to db await box.put(groupId, set); Logging.instance.log( - "Updated current anonymity set for ${coin.name} with group ID $groupId", + "Updated current anonymity set for ${cryptoCurrency.identifier} with group ID $groupId", level: LogLevel.Info, ); } @@ -99,8 +108,9 @@ class CachedElectrumXClient { return set; } catch (e, s) { Logging.instance.log( - "Failed to process CachedElectrumX.getAnonymitySet(): $e\n$s", - level: LogLevel.Error); + "Failed to process CachedElectrumX.getAnonymitySet(): $e\n$s", + level: LogLevel.Error, + ); rethrow; } } @@ -108,11 +118,13 @@ class CachedElectrumXClient { Future<Map<String, dynamic>> getSparkAnonymitySet({ required String groupId, String blockhash = "", - required Coin coin, + required CryptoCurrency cryptoCurrency, required bool useOnlyCacheIfNotEmpty, }) async { try { - final box = await DB.instance.getSparkAnonymitySetCacheBox(coin: coin); + final box = await DB.instance.getSparkAnonymitySetCacheBox( + currency: cryptoCurrency, + ); final cachedSet = box.get(groupId) as Map?; Map<String, dynamic> set; @@ -152,7 +164,7 @@ class CachedElectrumXClient { // save set to db await box.put(groupId, set); Logging.instance.log( - "Updated current anonymity set for ${coin.name} with group ID $groupId", + "Updated current anonymity set for ${cryptoCurrency.identifier} with group ID $groupId", level: LogLevel.Info, ); } @@ -160,8 +172,9 @@ class CachedElectrumXClient { return set; } catch (e, s) { Logging.instance.log( - "Failed to process CachedElectrumX.getSparkAnonymitySet(): $e\n$s", - level: LogLevel.Error); + "Failed to process CachedElectrumX.getSparkAnonymitySet(): $e\n$s", + level: LogLevel.Error, + ); rethrow; } } @@ -182,11 +195,11 @@ class CachedElectrumXClient { /// ElectrumX api only called if the tx does not exist in local db Future<Map<String, dynamic>> getTransaction({ required String txHash, - required Coin coin, + required CryptoCurrency cryptoCurrency, bool verbose = true, }) async { try { - final box = await DB.instance.getTxCacheBox(coin: coin); + final box = await DB.instance.getTxCacheBox(currency: cryptoCurrency); final cachedTx = box.get(txHash) as Map?; if (cachedTx == null) { @@ -213,22 +226,24 @@ class CachedElectrumXClient { } } catch (e, s) { Logging.instance.log( - "Failed to process CachedElectrumX.getTransaction(): $e\n$s", - level: LogLevel.Error); + "Failed to process CachedElectrumX.getTransaction(): $e\n$s", + level: LogLevel.Error, + ); rethrow; } } Future<List<String>> getUsedCoinSerials({ - required Coin coin, + required CryptoCurrency cryptoCurrency, int startNumber = 0, }) async { try { - final box = await DB.instance.getUsedSerialsCacheBox(coin: coin); + final box = + await DB.instance.getUsedSerialsCacheBox(currency: cryptoCurrency); final _list = box.get("serials") as List?; - Set<String> cachedSerials = + final Set<String> cachedSerials = _list == null ? {} : List<String>.from(_list).toSet(); startNumber = max( @@ -269,14 +284,16 @@ class CachedElectrumXClient { } Future<Set<String>> getSparkUsedCoinsTags({ - required Coin coin, + required CryptoCurrency cryptoCurrency, }) async { try { - final box = await DB.instance.getSparkUsedCoinsTagsCacheBox(coin: coin); + final box = await DB.instance.getSparkUsedCoinsTagsCacheBox( + currency: cryptoCurrency, + ); final _list = box.get("tags") as List?; - Set<String> cachedTags = + final Set<String> cachedTags = _list == null ? {} : List<String>.from(_list).toSet(); final startNumber = max( @@ -314,8 +331,9 @@ class CachedElectrumXClient { } /// Clear all cached transactions for the specified coin - Future<void> clearSharedTransactionCache({required Coin coin}) async { - await DB.instance.clearSharedTransactionCache(coin: coin); - await DB.instance.closeAnonymitySetCacheBox(coin: coin); + Future<void> clearSharedTransactionCache( + {required CryptoCurrency cryptoCurrency}) async { + await DB.instance.clearSharedTransactionCache(currency: cryptoCurrency); + await DB.instance.closeAnonymitySetCacheBox(currency: cryptoCurrency); } } diff --git a/lib/models/add_wallet_list_entity/add_wallet_list_entity.dart b/lib/models/add_wallet_list_entity/add_wallet_list_entity.dart index f59725f6b..b9fcdf1a0 100644 --- a/lib/models/add_wallet_list_entity/add_wallet_list_entity.dart +++ b/lib/models/add_wallet_list_entity/add_wallet_list_entity.dart @@ -9,10 +9,10 @@ */ import 'package:equatable/equatable.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; abstract class AddWalletListEntity extends Equatable { - Coin get coin; + CryptoCurrency get cryptoCurrency; String get name; String get ticker; } diff --git a/lib/models/add_wallet_list_entity/sub_classes/coin_entity.dart b/lib/models/add_wallet_list_entity/sub_classes/coin_entity.dart index 10e78688f..99fd2754c 100644 --- a/lib/models/add_wallet_list_entity/sub_classes/coin_entity.dart +++ b/lib/models/add_wallet_list_entity/sub_classes/coin_entity.dart @@ -9,22 +9,22 @@ */ import 'package:stackwallet/models/add_wallet_list_entity/add_wallet_list_entity.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; class CoinEntity extends AddWalletListEntity { CoinEntity(this._coin); - final Coin _coin; + final CryptoCurrency _coin; @override - Coin get coin => _coin; + CryptoCurrency get cryptoCurrency => _coin; @override - String get name => coin.prettyName; + String get name => cryptoCurrency.prettyName; @override - String get ticker => coin.ticker; + String get ticker => cryptoCurrency.ticker; @override - List<Object?> get props => [coin, name, ticker]; + List<Object?> get props => [cryptoCurrency.identifier, name, ticker]; } diff --git a/lib/models/add_wallet_list_entity/sub_classes/eth_token_entity.dart b/lib/models/add_wallet_list_entity/sub_classes/eth_token_entity.dart index 000bc810f..4bea313d0 100644 --- a/lib/models/add_wallet_list_entity/sub_classes/eth_token_entity.dart +++ b/lib/models/add_wallet_list_entity/sub_classes/eth_token_entity.dart @@ -10,15 +10,17 @@ import 'package:stackwallet/models/add_wallet_list_entity/add_wallet_list_entity.dart'; import 'package:stackwallet/models/isar/models/ethereum/eth_contract.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/ethereum.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; class EthTokenEntity extends AddWalletListEntity { EthTokenEntity(this.token); final EthContract token; + // TODO: check other networks in future and handle differently? @override - Coin get coin => Coin.ethereum; + CryptoCurrency get cryptoCurrency => Ethereum(CryptoCurrencyNetwork.main); @override String get name => token.name; @@ -27,5 +29,6 @@ class EthTokenEntity extends AddWalletListEntity { String get ticker => token.symbol; @override - List<Object?> get props => [coin, name, ticker, token.address]; + List<Object?> get props => + [cryptoCurrency.identifier, name, ticker, token.address]; } diff --git a/lib/models/address_book_filter.dart b/lib/models/address_book_filter.dart index 578ffc8c9..daddba49e 100644 --- a/lib/models/address_book_filter.dart +++ b/lib/models/address_book_filter.dart @@ -9,46 +9,46 @@ */ import 'package:flutter/material.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; class AddressBookFilter extends ChangeNotifier { - AddressBookFilter(Set<Coin> coins) { + AddressBookFilter(Set<CryptoCurrency> coins) { _coins = coins; } - Set<Coin> _coins = {}; + Set<CryptoCurrency> _coins = {}; - Set<Coin> get coins => _coins; + Set<CryptoCurrency> get coins => _coins; - set coins(Set<Coin> coins) { + set coins(Set<CryptoCurrency> coins) { _coins = coins; notifyListeners(); } - void add(Coin coin, bool shouldNotifyListeners) { + void add(CryptoCurrency coin, bool shouldNotifyListeners) { _coins.add(coin); if (shouldNotifyListeners) { notifyListeners(); } } - void addAll(Iterable<Coin> coins, bool shouldNotifyListeners) { + void addAll(Iterable<CryptoCurrency> coins, bool shouldNotifyListeners) { _coins.addAll(coins); if (shouldNotifyListeners) { notifyListeners(); } } - void remove(Coin coin, bool shouldNotifyListeners) { - _coins.removeWhere((e) => e.name == coin.name); + void remove(CryptoCurrency coin, bool shouldNotifyListeners) { + _coins.removeWhere((e) => e.identifier == coin.identifier); if (shouldNotifyListeners) { notifyListeners(); } } - void removeMany(Set<Coin> coins, bool shouldNotifyListeners) { + void removeMany(Set<CryptoCurrency> coins, bool shouldNotifyListeners) { for (final coin in coins) { - _coins.removeWhere((e) => e.name == coin.name); + _coins.removeWhere((e) => e.identifier == coin.identifier); } if (shouldNotifyListeners) { notifyListeners(); diff --git a/lib/models/balance.dart b/lib/models/balance.dart index 9f4b36a1c..be2c80859 100644 --- a/lib/models/balance.dart +++ b/lib/models/balance.dart @@ -11,7 +11,7 @@ import 'dart:convert'; import 'package:stackwallet/utilities/amount/amount.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; class Balance { final Amount total; @@ -26,10 +26,10 @@ class Balance { required this.pendingSpendable, }); - factory Balance.zeroForCoin({required Coin coin}) { + factory Balance.zeroFor({required CryptoCurrency currency}) { final amount = Amount( rawValue: BigInt.zero, - fractionDigits: coin.decimals, + fractionDigits: currency.fractionDigits, ); return Balance( diff --git a/lib/models/contact_address_entry.dart b/lib/models/contact_address_entry.dart index 6f1ad1d54..f57ed6d4b 100644 --- a/lib/models/contact_address_entry.dart +++ b/lib/models/contact_address_entry.dart @@ -10,11 +10,12 @@ import 'dart:convert'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/supported_coins.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; @Deprecated("Use lib/models/isar/models/contact_entry.dart instead") class ContactAddressEntry { - final Coin coin; + final CryptoCurrency coin; final String address; final String label; final String? other; @@ -27,7 +28,7 @@ class ContactAddressEntry { }); ContactAddressEntry copyWith({ - Coin? coin, + CryptoCurrency? coin, String? address, String? label, String? other, @@ -42,7 +43,7 @@ class ContactAddressEntry { factory ContactAddressEntry.fromJson(Map<String, dynamic> jsonObject) { return ContactAddressEntry( - coin: Coin.values.byName(jsonObject["coin"] as String), + coin: SupportedCoins.getCryptoCurrencyFor(jsonObject["coin"] as String), address: jsonObject["address"] as String, label: jsonObject["label"] as String, other: jsonObject["other"] as String?, @@ -53,7 +54,7 @@ class ContactAddressEntry { return { "label": label, "address": address, - "coin": coin.name, + "coin": coin.identifier, "other": other ?? "", }; } diff --git a/lib/models/contact_address_entry_data.dart b/lib/models/contact_address_entry_data.dart index d7fb17684..545f40bac 100644 --- a/lib/models/contact_address_entry_data.dart +++ b/lib/models/contact_address_entry_data.dart @@ -10,8 +10,7 @@ import 'package:flutter/cupertino.dart'; import 'package:stackwallet/models/isar/models/contact_entry.dart'; -import 'package:stackwallet/utilities/address_utils.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; class AddressEntryData extends ChangeNotifier { late int id; @@ -20,7 +19,7 @@ class AddressEntryData extends ChangeNotifier { String? _addressLabel; String? _address; - Coin? _coin; + CryptoCurrency? _coin; String? get addressLabel => _addressLabel; @@ -36,9 +35,9 @@ class AddressEntryData extends ChangeNotifier { notifyListeners(); } - Coin? get coin => _coin; + CryptoCurrency? get coin => _coin; - set coin(Coin? coin) { + set coin(CryptoCurrency? coin) { _coin = coin; notifyListeners(); } @@ -73,12 +72,12 @@ class AddressEntryData extends ChangeNotifier { if (_address == null) { return false; } - return AddressUtils.validateAddress(_address!, _coin!); + return _coin!.validateAddress(_address!); } ContactAddressEntry buildAddressEntry() { return ContactAddressEntry() - ..coinName = coin!.name + ..coinName = coin!.identifier ..address = address! ..other = null ..label = addressLabel!; @@ -86,6 +85,6 @@ class AddressEntryData extends ChangeNotifier { @override String toString() { - return "AddressEntryData: { addressLabel: $addressLabel, address: $address, coin: ${coin?.name} }"; + return "AddressEntryData: { addressLabel: $addressLabel, address: $address, coin: ${coin?.identifier} }"; } } diff --git a/lib/models/isar/exchange_cache/currency.dart b/lib/models/isar/exchange_cache/currency.dart index 5a3915e08..0233cbe98 100644 --- a/lib/models/isar/exchange_cache/currency.dart +++ b/lib/models/isar/exchange_cache/currency.dart @@ -10,7 +10,7 @@ import 'package:isar/isar.dart'; import 'package:stackwallet/models/isar/exchange_cache/pair.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/supported_coins.dart'; part 'currency.g.dart'; @@ -161,7 +161,7 @@ class Currency { static bool checkIsStackCoin(String ticker) { try { - coinFromTickerCaseInsensitive(ticker); + SupportedCoins.getCryptoCurrencyForTicker(ticker); return true; } catch (_) { return false; diff --git a/lib/models/isar/models/block_explorer.dart b/lib/models/isar/models/block_explorer.dart index 05d832580..411ad4ec3 100644 --- a/lib/models/isar/models/block_explorer.dart +++ b/lib/models/isar/models/block_explorer.dart @@ -9,7 +9,8 @@ */ import 'package:isar/isar.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/supported_coins.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; part 'block_explorer.g.dart'; @@ -28,9 +29,9 @@ class TransactionBlockExplorer { late final String url; @ignore - Coin? get coin { + CryptoCurrency? get coin { try { - return coinFromTickerCaseInsensitive(ticker); + return SupportedCoins.getCryptoCurrencyForTicker(ticker); } catch (_) { return null; } diff --git a/lib/models/isar/models/contact_entry.dart b/lib/models/isar/models/contact_entry.dart index 6289e8d18..b3a0fe809 100644 --- a/lib/models/isar/models/contact_entry.dart +++ b/lib/models/isar/models/contact_entry.dart @@ -9,7 +9,8 @@ */ import 'package:isar/isar.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/supported_coins.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; part 'contact_entry.g.dart'; @@ -36,7 +37,7 @@ class ContactEntry { @ignore List<ContactAddressEntry> get addressesSorted { final List<ContactAddressEntry> sorted = []; - for (final coin in Coin.values) { + for (final coin in SupportedCoins.cryptocurrencies) { final slice = addresses.where((e) => e.coin == coin).toList(); if (slice.isNotEmpty) { slice.sort( @@ -56,13 +57,13 @@ class ContactEntry { List<ContactAddressEntry>? addresses, bool? isFavorite, }) { - List<ContactAddressEntry> _addresses = []; + final List<ContactAddressEntry> _addresses = []; if (addresses == null) { - for (var e in this.addresses) { + for (final e in this.addresses) { _addresses.add(e.copyWith()); } } else { - for (var e in addresses) { + for (final e in addresses) { _addresses.add(e.copyWith()); } } @@ -101,18 +102,18 @@ class ContactAddressEntry { late final String? other; @ignore - Coin get coin => Coin.values.byName(coinName); + CryptoCurrency get coin => SupportedCoins.getCryptoCurrencyFor(coinName); ContactAddressEntry(); ContactAddressEntry copyWith({ - Coin? coin, + CryptoCurrency? coin, String? address, String? label, String? other, }) { return ContactAddressEntry() - ..coinName = coin?.name ?? coinName + ..coinName = coin?.identifier ?? coinName ..address = address ?? this.address ..label = label ?? this.label ..other = other ?? this.other; @@ -122,7 +123,7 @@ class ContactAddressEntry { return { "label": label, "address": address, - "coin": coin.name, + "coin": coin.identifier, "other": other ?? "", }; } diff --git a/lib/models/isar/stack_theme.dart b/lib/models/isar/stack_theme.dart index 09f42b1b6..b33ca274d 100644 --- a/lib/models/isar/stack_theme.dart +++ b/lib/models/isar/stack_theme.dart @@ -13,7 +13,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:isar/isar.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/supported_coins.dart'; import 'package:stackwallet/utilities/extensions/impl/box_shadow.dart'; import 'package:stackwallet/utilities/extensions/impl/gradient.dart'; import 'package:stackwallet/utilities/extensions/impl/string.dart'; @@ -1482,10 +1482,10 @@ class StackTheme { // ==== coinColors ===================================================== @ignore - Map<Coin, Color> get coinColors => + Map<String, Color> get coinColors => _coinColors ??= parseCoinColors(coinColorsJsonString); @ignore - Map<Coin, Color>? _coinColors; + Map<String, Color>? _coinColors; late final String coinColorsJsonString; // ==== assets ===================================================== @@ -1851,20 +1851,21 @@ class StackTheme { } /// parse coin colors json and fetch color or use default - static Map<Coin, Color> parseCoinColors(String jsonString) { + static Map<String, Color> parseCoinColors(String jsonString) { final json = jsonDecode(jsonString) as Map; final map = Map<String, dynamic>.from(json); - final Map<Coin, Color> result = {}; + final Map<String, Color> result = {}; - for (final coin in Coin.values.map((e) => e.mainNetVersion)) { - if (map[coin.name] is String) { - result[coin] = Color( - (map[coin.name] as String).toBigIntFromHex.toInt(), + for (final mainNetId + in SupportedCoins.cryptocurrencies.map((e) => e.mainNetId)) { + if (map[mainNetId] is String) { + result[mainNetId] = Color( + (map[mainNetId] as String).toBigIntFromHex.toInt(), ); } else { Logging.instance.log( - "Color not found in theme for $coin", + "Color not found in theme for $mainNetId", level: LogLevel.Error, ); } @@ -2080,31 +2081,31 @@ class ThemeAssetsV2 implements IThemeAssets { late final String coinPlaceholder; @ignore - Map<Coin, String> get coinIcons => _coinIcons ??= parseCoinAssetsString( + Map<String, String> get coinIcons => _coinIcons ??= parseCoinAssetsString( coinIconsString, placeHolder: coinPlaceholder, ); @ignore - Map<Coin, String>? _coinIcons; + Map<String, String>? _coinIcons; late final String coinIconsString; @ignore - Map<Coin, String> get coinImages => _coinImages ??= parseCoinAssetsString( + Map<String, String> get coinImages => _coinImages ??= parseCoinAssetsString( coinImagesString, placeHolder: coinPlaceholder, ); @ignore - Map<Coin, String>? _coinImages; + Map<String, String>? _coinImages; late final String coinImagesString; @ignore - Map<Coin, String> get coinSecondaryImages => + Map<String, String> get coinSecondaryImages => _coinSecondaryImages ??= parseCoinAssetsString( coinSecondaryImagesString, placeHolder: coinPlaceholder, ); @ignore - Map<Coin, String>? _coinSecondaryImages; + Map<String, String>? _coinSecondaryImages; late final String coinSecondaryImagesString; ThemeAssetsV2(); @@ -2166,17 +2167,17 @@ class ThemeAssetsV2 implements IThemeAssets { return jsonEncode(map); } - static Map<Coin, String> parseCoinAssetsString( + static Map<String, String> parseCoinAssetsString( String jsonString, { required String placeHolder, }) { final json = jsonDecode(jsonString) as Map; final map = Map<String, dynamic>.from(json); - final Map<Coin, String> result = {}; + final Map<String, String> result = {}; - for (final coin in Coin.values) { - result[coin] = map[coin.name] as String? ?? placeHolder; + for (final coin in SupportedCoins.cryptocurrencies) { + result[coin.mainNetId] = map[coin.mainNetId] as String? ?? placeHolder; } return result; @@ -2350,35 +2351,35 @@ class ThemeAssetsV3 implements IThemeAssets { late final String? dummy3; @ignore - Map<Coin, String> get coinIcons => _coinIcons ??= parseCoinAssetsString( + Map<String, String> get coinIcons => _coinIcons ??= parseCoinAssetsString( coinIconsString, placeHolder: coinPlaceholder, ); @ignore - Map<Coin, String>? _coinIcons; + Map<String, String>? _coinIcons; late final String coinIconsString; @ignore - Map<Coin, String> get coinImages => _coinImages ??= parseCoinAssetsString( + Map<String, String> get coinImages => _coinImages ??= parseCoinAssetsString( coinImagesString, placeHolder: coinPlaceholder, ); @ignore - Map<Coin, String>? _coinImages; + Map<String, String>? _coinImages; late final String coinImagesString; @ignore - Map<Coin, String> get coinSecondaryImages => + Map<String, String> get coinSecondaryImages => _coinSecondaryImages ??= parseCoinAssetsString( coinSecondaryImagesString, placeHolder: coinPlaceholder, ); @ignore - Map<Coin, String>? _coinSecondaryImages; + Map<String, String>? _coinSecondaryImages; late final String coinSecondaryImagesString; @ignore - Map<Coin, String>? get coinCardImages => + Map<String, String>? get coinCardImages => _coinCardImages ??= coinCardImagesString == null ? null : parseCoinAssetsString( @@ -2386,11 +2387,11 @@ class ThemeAssetsV3 implements IThemeAssets { placeHolder: coinPlaceholder, ); @ignore - Map<Coin, String>? _coinCardImages; + Map<String, String>? _coinCardImages; late final String? coinCardImagesString; @ignore - Map<Coin, String>? get coinCardFavoritesImages => + Map<String, String>? get coinCardFavoritesImages => _coinCardFavoritesImages ??= coinCardFavoritesImagesString == null ? null : parseCoinAssetsString( @@ -2398,7 +2399,7 @@ class ThemeAssetsV3 implements IThemeAssets { placeHolder: coinPlaceholder, ); @ignore - Map<Coin, String>? _coinCardFavoritesImages; + Map<String, String>? _coinCardFavoritesImages; @Name("otherStringParam1") late final String? coinCardFavoritesImagesString; @@ -2501,19 +2502,18 @@ class ThemeAssetsV3 implements IThemeAssets { return jsonEncode(map); } - static Map<Coin, String> parseCoinAssetsString( + static Map<String, String> parseCoinAssetsString( String jsonString, { required String placeHolder, }) { final json = jsonDecode(jsonString) as Map; final map = Map<String, dynamic>.from(json); - final Map<Coin, String> result = {}; + final Map<String, String> result = {}; - for (final coin in Coin.values) { - result[coin] = map[coin.name] as String? ?? placeHolder; - - result[coin] = prependIfNeeded(result[coin]!); + for (final coin in SupportedCoins.cryptocurrencies) { + result[coin.mainNetId] = map[coin.mainNetId] as String? ?? placeHolder; + result[coin.mainNetId] = prependIfNeeded(result[coin.mainNetId]!); } return result; diff --git a/lib/models/paymint/transactions_model.dart b/lib/models/paymint/transactions_model.dart index db2dd2eee..c00f31565 100644 --- a/lib/models/paymint/transactions_model.dart +++ b/lib/models/paymint/transactions_model.dart @@ -11,8 +11,6 @@ import 'package:dart_numerics/dart_numerics.dart'; import 'package:decimal/decimal.dart'; import 'package:hive/hive.dart'; -import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; part '../type_adaptors/transactions_model.g.dart'; @@ -236,19 +234,11 @@ class Transaction { timestamp: json['timestamp'] as int? ?? (DateTime.now().millisecondsSinceEpoch ~/ 1000), txType: json['txType'] as String, - amount: (Decimal.parse(json["amount"].toString()) * - Decimal.fromInt(Constants.satsPerCoin(Coin - .firo).toInt())) // dirty hack but we need 8 decimal places here to keep consistent data structure - .toBigInt() - .toInt(), + amount: _parse(json["amount"].toString()), aliens: [], worthNow: json['worthNow'] as String, worthAtBlockTimestamp: json['worthAtBlockTimestamp'] as String? ?? "0", - fees: (Decimal.parse(json["fees"].toString()) * - Decimal.fromInt(Constants.satsPerCoin(Coin - .firo).toInt())) // dirty hack but we need 8 decimal places here to keep consistent data structure - .toBigInt() - .toInt(), + fees: _parse(json["fees"].toString()), inputSize: json['inputSize'] as int? ?? 0, outputSize: json['outputSize'] as int? ?? 0, inputs: [], @@ -411,12 +401,7 @@ class Output { scriptpubkeyAsm: json['scriptPubKey']['asm'] as String?, scriptpubkeyType: json['scriptPubKey']['type'] as String?, scriptpubkeyAddress: address, - value: (Decimal.parse( - (json["value"] ?? 0).toString()) * - Decimal.fromInt(Constants.satsPerCoin(Coin - .firo).toInt())) // dirty hack but we need 8 decimal places here to keep consistent data structure - .toBigInt() - .toInt(), + value: _parse((json["value"] ?? 0).toString()), ); } catch (s, e) { return Output( @@ -425,11 +410,11 @@ class Output { scriptpubkeyAsm: "", scriptpubkeyType: "", scriptpubkeyAddress: "", - value: (Decimal.parse(0.toString()) * - Decimal.fromInt(Constants.satsPerCoin(Coin - .firo).toInt())) // dirty hack but we need 8 decimal places here to keep consistent data structure - .toBigInt() - .toInt()); + value: _parse(0.toString())); } } } + +int _parse(String value) { + return (Decimal.parse(value) * Decimal.fromInt(8)).toBigInt().toInt(); +} diff --git a/lib/models/wallet_restore_state.dart b/lib/models/wallet_restore_state.dart index 37598651d..e325cad4d 100644 --- a/lib/models/wallet_restore_state.dart +++ b/lib/models/wallet_restore_state.dart @@ -9,14 +9,14 @@ */ import 'package:flutter/material.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/stack_restoring_status.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/wallet/wallet.dart'; class WalletRestoreState extends ChangeNotifier { final String walletId; final String walletName; - final Coin coin; + final CryptoCurrency coin; late StackRestoringStatus _restoringStatus; Wallet? wallet; String? address; diff --git a/lib/notifications/notification_card.dart b/lib/notifications/notification_card.dart index ada6400f6..1135a478c 100644 --- a/lib/notifications/notification_card.dart +++ b/lib/notifications/notification_card.dart @@ -15,10 +15,10 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/models/isar/stack_theme.dart'; import 'package:stackwallet/models/notification_model.dart'; +import 'package:stackwallet/supported_coins.dart'; import 'package:stackwallet/themes/coin_icon_provider.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/themes/theme_providers.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/format.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; @@ -44,7 +44,8 @@ class NotificationCard extends ConsumerWidget { String coinIconPath(IThemeAssets assets, WidgetRef ref) { try { - final coin = coinFromPrettyName(notification.coinName); + final coin = + SupportedCoins.getCryptoCurrencyByPrettyName(notification.coinName); return ref.read(coinIconProvider(coin)); } catch (_) { return notification.iconAssetName; diff --git a/lib/pages/add_wallet_views/add_wallet_view/add_wallet_view.dart b/lib/pages/add_wallet_views/add_wallet_view/add_wallet_view.dart index 34048fcbb..267358b54 100644 --- a/lib/pages/add_wallet_views/add_wallet_view/add_wallet_view.dart +++ b/lib/pages/add_wallet_views/add_wallet_view/add_wallet_view.dart @@ -28,13 +28,17 @@ import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/sub_widgets/e import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/sub_widgets/next_button.dart'; import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart'; import 'package:stackwallet/providers/providers.dart'; +import 'package:stackwallet/supported_coins.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/default_eth_tokens.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/bitcoin_frost.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/monero.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/wownero.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/background.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart'; @@ -61,10 +65,14 @@ class _AddWalletViewState extends ConsumerState<AddWalletView> { String _searchTerm = ""; - final List<Coin> _coinsTestnet = [ - ...Coin.values.where((e) => e.isTestNet), + final _coinsTestnet = [ + ...SupportedCoins.cryptocurrencies + .where((e) => e.network == CryptoCurrencyNetwork.test), + ]; + final _coins = [ + ...SupportedCoins.cryptocurrencies + .where((e) => e.network == CryptoCurrencyNetwork.main), ]; - final List<Coin> _coins = [...Coin.values.where((e) => !e.isTestNet)]; final List<AddWalletListEntity> coinEntities = []; final List<EthTokenEntity> tokenEntities = []; @@ -81,7 +89,7 @@ class _AddWalletViewState extends ConsumerState<AddWalletView> { (e) => e.ticker.toLowerCase().contains(lowercaseTerm) || e.name.toLowerCase().contains(lowercaseTerm) || - e.coin.name.toLowerCase().contains(lowercaseTerm) || + e.cryptoCurrency.identifier.toLowerCase().contains(lowercaseTerm) || (e is EthTokenEntity && e.token.address.toLowerCase().contains(lowercaseTerm)), ); @@ -129,15 +137,13 @@ class _AddWalletViewState extends ConsumerState<AddWalletView> { _searchFocusNode = FocusNode(); // _coinsTestnet.remove(Coin.firoTestNet); if (Platform.isWindows) { - _coins.remove(Coin.monero); - _coins.remove(Coin.wownero); + _coins.removeWhere((e) => e is Monero || e is Wownero); } else if (Platform.isLinux) { - _coins.remove(Coin.wownero); + _coins.removeWhere((e) => e is Wownero); } if (Util.isDesktop && !kDebugMode) { - _coins.remove(Coin.bitcoinFrost); - _coins.remove(Coin.bitcoinFrostTestNet); + _coins.removeWhere((e) => e is BitcoinFrost); } coinEntities.addAll(_coins.map((e) => CoinEntity(e))); diff --git a/lib/pages/add_wallet_views/add_wallet_view/sub_widgets/coin_select_item.dart b/lib/pages/add_wallet_views/add_wallet_view/sub_widgets/coin_select_item.dart index 410ebc7bd..18527b059 100644 --- a/lib/pages/add_wallet_views/add_wallet_view/sub_widgets/coin_select_item.dart +++ b/lib/pages/add_wallet_views/add_wallet_view/sub_widgets/coin_select_item.dart @@ -29,9 +29,9 @@ import 'package:stackwallet/utilities/util.dart'; class CoinSelectItem extends ConsumerWidget { const CoinSelectItem({ - Key? key, + super.key, required this.entity, - }) : super(key: key); + }); final AddWalletListEntity entity; @@ -90,7 +90,7 @@ class CoinSelectItem extends ConsumerWidget { ) : SvgPicture.file( File( - ref.watch(coinIconProvider(entity.coin)), + ref.watch(coinIconProvider(entity.cryptoCurrency)), ), width: 26, height: 26, diff --git a/lib/pages/add_wallet_views/create_or_restore_wallet_view/create_or_restore_wallet_view.dart b/lib/pages/add_wallet_views/create_or_restore_wallet_view/create_or_restore_wallet_view.dart index ef4d55319..49531bf9c 100644 --- a/lib/pages/add_wallet_views/create_or_restore_wallet_view/create_or_restore_wallet_view.dart +++ b/lib/pages/add_wallet_views/create_or_restore_wallet_view/create_or_restore_wallet_view.dart @@ -24,9 +24,9 @@ import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart'; class CreateOrRestoreWalletView extends StatelessWidget { const CreateOrRestoreWalletView({ - Key? key, + super.key, required this.entity, - }) : super(key: key); + }); static const routeName = "/createOrRestoreWallet"; @@ -57,7 +57,7 @@ class CreateOrRestoreWalletView extends StatelessWidget { flex: 10, ),*/ CreateRestoreWalletTitle( - coin: entity.coin, + coin: entity.cryptoCurrency, isDesktop: isDesktop, ), const SizedBox( @@ -73,7 +73,7 @@ class CreateOrRestoreWalletView extends StatelessWidget { height: 32, ), CoinImage( - coin: entity.coin, + coin: entity.cryptoCurrency, width: isDesktop ? 324 : MediaQuery.of(context).size.width / 1.6, @@ -85,7 +85,7 @@ class CreateOrRestoreWalletView extends StatelessWidget { height: 32, ), CreateWalletButtonGroup( - coin: entity.coin, + coin: entity.cryptoCurrency, isDesktop: isDesktop, ), /*const Spacer( @@ -129,7 +129,7 @@ class CreateOrRestoreWalletView extends StatelessWidget { flex: 2, ), CoinImage( - coin: entity.coin, + coin: entity.cryptoCurrency, width: isDesktop ? 324 : MediaQuery.of(context).size.width / 1.6, @@ -141,7 +141,7 @@ class CreateOrRestoreWalletView extends StatelessWidget { flex: 2, ), CreateRestoreWalletTitle( - coin: entity.coin, + coin: entity.cryptoCurrency, isDesktop: isDesktop, ), const SizedBox( @@ -154,7 +154,7 @@ class CreateOrRestoreWalletView extends StatelessWidget { flex: 5, ), CreateWalletButtonGroup( - coin: entity.coin, + coin: entity.cryptoCurrency, isDesktop: isDesktop, ), ], diff --git a/lib/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/coin_image.dart b/lib/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/coin_image.dart index 0d13044be..f13aee957 100644 --- a/lib/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/coin_image.dart +++ b/lib/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/coin_image.dart @@ -14,18 +14,18 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/themes/coin_image_provider.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; class CoinImage extends ConsumerWidget { const CoinImage({ - Key? key, + super.key, required this.coin, this.width, this.height, - }) : super(key: key); + }); - final Coin coin; + final CryptoCurrency coin; final double? width; final double? height; diff --git a/lib/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/create_or_restore_wallet_title.dart b/lib/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/create_or_restore_wallet_title.dart index ae7e917c8..319d8daf7 100644 --- a/lib/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/create_or_restore_wallet_title.dart +++ b/lib/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/create_or_restore_wallet_title.dart @@ -9,17 +9,17 @@ */ import 'package:flutter/material.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; class CreateRestoreWalletTitle extends StatelessWidget { const CreateRestoreWalletTitle({ - Key? key, + super.key, required this.coin, required this.isDesktop, - }) : super(key: key); + }); - final Coin coin; + final CryptoCurrency coin; final bool isDesktop; @override diff --git a/lib/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/create_wallet_button_group.dart b/lib/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/create_wallet_button_group.dart index 36c914fd8..2120f6c4d 100644 --- a/lib/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/create_wallet_button_group.dart +++ b/lib/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/create_wallet_button_group.dart @@ -14,18 +14,19 @@ import 'package:flutter/material.dart'; import 'package:stackwallet/pages/add_wallet_views/name_your_wallet_view/name_your_wallet_view.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/enums/add_wallet_type_enum.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/wownero.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:tuple/tuple.dart'; class CreateWalletButtonGroup extends StatelessWidget { const CreateWalletButtonGroup({ - Key? key, + super.key, required this.coin, required this.isDesktop, - }) : super(key: key); + }); - final Coin coin; + final CryptoCurrency coin; final bool isDesktop; @override @@ -34,7 +35,7 @@ class CreateWalletButtonGroup extends StatelessWidget { crossAxisAlignment: isDesktop ? CrossAxisAlignment.center : CrossAxisAlignment.stretch, children: [ - if (Platform.isAndroid || coin != Coin.wownero) + if (Platform.isAndroid || coin is! Wownero) ConstrainedBox( constraints: BoxConstraints( minHeight: isDesktop ? 70 : 0, @@ -61,7 +62,7 @@ class CreateWalletButtonGroup extends StatelessWidget { ), ), ), - if (Platform.isAndroid || coin != Coin.wownero) + if (Platform.isAndroid || coin is! Wownero) SizedBox( height: isDesktop ? 16 : 12, ), diff --git a/lib/pages/add_wallet_views/frost_ms/new/steps/frost_create_step_5.dart b/lib/pages/add_wallet_views/frost_ms/new/steps/frost_create_step_5.dart index 586a1c189..d64c163e3 100644 --- a/lib/pages/add_wallet_views/frost_ms/new/steps/frost_create_step_5.dart +++ b/lib/pages/add_wallet_views/frost_ms/new/steps/frost_create_step_5.dart @@ -143,7 +143,7 @@ class _FrostCreateStep5State extends ConsumerState<FrostCreateStep5> { final data = ref.read(pFrostScaffoldArgs)!; final info = WalletInfo.createNew( - coin: data.info.frostCurrency.coin, + coin: data.info.frostCurrency, name: data.info.walletName, ); diff --git a/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_1c.dart b/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_1c.dart index 2bbfef1de..25267beed 100644 --- a/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_1c.dart +++ b/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_1c.dart @@ -49,7 +49,7 @@ class _FrostReshareStep1cState extends ConsumerState<FrostReshareStep1c> { final info = WalletInfo.createNew( name: data.info.walletName, - coin: data.info.frostCurrency.coin, + coin: data.info.frostCurrency, ); final wallet = IncompleteFrostWallet(); diff --git a/lib/pages/add_wallet_views/frost_ms/restore/restore_frost_ms_wallet_view.dart b/lib/pages/add_wallet_views/frost_ms/restore/restore_frost_ms_wallet_view.dart index 03a7ee8bf..138dd09da 100644 --- a/lib/pages/add_wallet_views/frost_ms/restore/restore_frost_ms_wallet_view.dart +++ b/lib/pages/add_wallet_views/frost_ms/restore/restore_frost_ms_wallet_view.dart @@ -75,7 +75,7 @@ class _RestoreFrostMsWalletViewState final myName = participants[myNameIndex]; final info = WalletInfo.createNew( - coin: widget.frostCurrency.coin, + coin: widget.frostCurrency, name: widget.walletName, ); diff --git a/lib/pages/add_wallet_views/name_your_wallet_view/name_your_wallet_view.dart b/lib/pages/add_wallet_views/name_your_wallet_view/name_your_wallet_view.dart index 3cfeb6bbd..c0e94fdd1 100644 --- a/lib/pages/add_wallet_views/name_your_wallet_view/name_your_wallet_view.dart +++ b/lib/pages/add_wallet_views/name_your_wallet_view/name_your_wallet_view.dart @@ -26,12 +26,11 @@ import 'package:stackwallet/providers/ui/verify_recovery_phrase/mnemonic_word_co import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/add_wallet_type_enum.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/name_generator.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; -import 'package:stackwallet/wallets/crypto_currency/coins/bitcoin_frost.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; +import 'package:stackwallet/wallets/crypto_currency/intermediate/frost_currency.dart'; import 'package:stackwallet/wallets/isar/models/wallet_info.dart'; import 'package:stackwallet/widgets/background.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; @@ -48,15 +47,15 @@ import 'package:tuple/tuple.dart'; class NameYourWalletView extends ConsumerStatefulWidget { const NameYourWalletView({ - Key? key, + super.key, required this.addWalletType, required this.coin, - }) : super(key: key); + }); static const routeName = "/nameYourWallet"; final AddWalletType addWalletType; - final Coin coin; + final CryptoCurrency coin; @override ConsumerState<NameYourWalletView> createState() => _NameYourWalletViewState(); @@ -64,7 +63,7 @@ class NameYourWalletView extends ConsumerStatefulWidget { class _NameYourWalletViewState extends ConsumerState<NameYourWalletView> { late final AddWalletType addWalletType; - late final Coin coin; + late final CryptoCurrency coin; late TextEditingController textEditingController; late FocusNode textFieldFocusNode; @@ -96,7 +95,7 @@ class _NameYourWalletViewState extends ConsumerState<NameYourWalletView> { if (mounted) { ref.read(mnemonicWordCountStateProvider.state).state = - Constants.possibleLengthsForCoin(coin).last; + coin.possibleMnemonicLengths.last; ref.read(pNewWalletOptions.notifier).state = null; switch (widget.addWalletType) { @@ -244,7 +243,7 @@ class _NameYourWalletViewState extends ConsumerState<NameYourWalletView> { height: isDesktop ? 0 : 16, ), Text( - "Name your ${coin.prettyName} ${coin.isFrost ? "multisig " : ""}wallet", + "Name your ${coin.prettyName} ${coin is FrostCurrency ? "multisig " : ""}wallet", textAlign: TextAlign.center, style: isDesktop ? STextStyles.desktopH2(context) @@ -254,7 +253,7 @@ class _NameYourWalletViewState extends ConsumerState<NameYourWalletView> { height: isDesktop ? 16 : 8, ), Text( - "Enter a label for your wallet (e.g. ${coin.isFrost ? "Multisig" : "Savings"})", + "Enter a label for your wallet (e.g. ${coin is FrostCurrency ? "Multisig" : "Savings"})", textAlign: TextAlign.center, style: isDesktop ? STextStyles.desktopSubtitleH2(context) @@ -383,7 +382,7 @@ class _NameYourWalletViewState extends ConsumerState<NameYourWalletView> { const SizedBox( height: 32, ), - if (widget.coin.isFrost) + if (widget.coin is FrostCurrency) if (widget.addWalletType == AddWalletType.Restore) PrimaryButton( label: "Next", @@ -395,15 +394,13 @@ class _NameYourWalletViewState extends ConsumerState<NameYourWalletView> { RestoreFrostMsWalletView.routeName, arguments: ( walletName: name, - // TODO: [prio=med] this will cause issues if frost is ever applied to other coins - frostCurrency: coin.isTestNet - ? BitcoinFrost(CryptoCurrencyNetwork.test) - : BitcoinFrost(CryptoCurrencyNetwork.main), + frostCurrency: coin, ), ); }, ), - if (widget.coin.isFrost && widget.addWalletType == AddWalletType.New) + if (widget.coin is FrostCurrency && + widget.addWalletType == AddWalletType.New) Column( children: [ PrimaryButton( @@ -416,10 +413,7 @@ class _NameYourWalletViewState extends ConsumerState<NameYourWalletView> { CreateNewFrostMsWalletView.routeName, arguments: ( walletName: name, - // TODO: [prio=med] this will cause issues if frost is ever applied to other coins - frostCurrency: coin.isTestNet - ? BitcoinFrost(CryptoCurrencyNetwork.test) - : BitcoinFrost(CryptoCurrencyNetwork.main), + frostCurrency: coin, ), ); }, @@ -437,10 +431,7 @@ class _NameYourWalletViewState extends ConsumerState<NameYourWalletView> { SelectNewFrostImportTypeView.routeName, arguments: ( walletName: name, - // TODO: [prio=med] this will cause issues if frost is ever applied to other coins - frostCurrency: coin.isTestNet - ? BitcoinFrost(CryptoCurrencyNetwork.test) - : BitcoinFrost(CryptoCurrencyNetwork.main), + frostCurrency: coin, ), ); }, @@ -480,7 +471,7 @@ class _NameYourWalletViewState extends ConsumerState<NameYourWalletView> { // ), ], ), - if (!widget.coin.isFrost) + if (widget.coin is! FrostCurrency) ConstrainedBox( constraints: BoxConstraints( minWidth: isDesktop ? 480 : 0, diff --git a/lib/pages/add_wallet_views/new_wallet_options/new_wallet_options_view.dart b/lib/pages/add_wallet_views/new_wallet_options/new_wallet_options_view.dart index f6d3075b2..a8e9c3a8a 100644 --- a/lib/pages/add_wallet_views/new_wallet_options/new_wallet_options_view.dart +++ b/lib/pages/add_wallet_views/new_wallet_options/new_wallet_options_view.dart @@ -11,9 +11,9 @@ import 'package:stackwallet/providers/ui/verify_recovery_phrase/mnemonic_word_co import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/background.dart'; import 'package:stackwallet/widgets/conditional_parent.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; @@ -26,7 +26,8 @@ import 'package:tuple/tuple.dart'; final pNewWalletOptions = StateProvider<({String mnemonicPassphrase, int mnemonicWordsCount})?>( - (ref) => null); + (ref) => null, +); enum NewWalletOptions { Default, @@ -35,15 +36,15 @@ enum NewWalletOptions { class NewWalletOptionsView extends ConsumerStatefulWidget { const NewWalletOptionsView({ - Key? key, + super.key, required this.walletName, required this.coin, - }) : super(key: key); + }); static const routeName = "/newWalletOptionsView"; final String walletName; - final Coin coin; + final CryptoCurrency coin; @override ConsumerState<NewWalletOptionsView> createState() => @@ -74,7 +75,7 @@ class _NewWalletOptionsViewState extends ConsumerState<NewWalletOptionsView> { @override Widget build(BuildContext context) { - final lengths = Constants.possibleLengthsForCoin(widget.coin).toList(); + final lengths = widget.coin.possibleMnemonicLengths; return ConditionalParent( condition: Util.isDesktop, builder: (child) => DesktopScaffold( @@ -339,7 +340,8 @@ class _NewWalletOptionsViewState extends ConsumerState<NewWalletOptionsView> { ), GestureDetector( key: const Key( - "mnemonicPassphraseFieldShowPasswordButtonKey"), + "mnemonicPassphraseFieldShowPasswordButtonKey", + ), onTap: () async { setState(() { hidePassword = !hidePassword; 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 8e3f8750f..e6f620a02 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 @@ -25,13 +25,14 @@ import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/services/transaction_notification_tracker.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/default_nodes.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/monero.dart'; import 'package:stackwallet/wallets/crypto_currency/coins/tezos.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/wownero.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/isar/models/wallet_info.dart'; import 'package:stackwallet/wallets/wallet/wallet.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/mnemonic_interface.dart'; @@ -45,14 +46,14 @@ import 'package:tuple/tuple.dart'; class NewWalletRecoveryPhraseWarningView extends ConsumerStatefulWidget { const NewWalletRecoveryPhraseWarningView({ - Key? key, + super.key, required this.coin, required this.walletName, - }) : super(key: key); + }); static const routeName = "/newWalletRecoveryPhraseWarning"; - final Coin coin; + final CryptoCurrency coin; final String walletName; @override @@ -62,7 +63,7 @@ class NewWalletRecoveryPhraseWarningView extends ConsumerStatefulWidget { class _NewWalletRecoveryPhraseWarningViewState extends ConsumerState<NewWalletRecoveryPhraseWarningView> { - late final Coin coin; + late final CryptoCurrency coin; late final String walletName; late final bool isDesktop; @@ -79,8 +80,8 @@ class _NewWalletRecoveryPhraseWarningViewState debugPrint("BUILD: $runtimeType"); final options = ref.read(pNewWalletOptions.state).state; - final seedCount = options?.mnemonicWordsCount ?? - Constants.defaultSeedPhraseLengthFor(coin: coin); + final seedCount = + options?.mnemonicWordsCount ?? coin.defaultSeedPhraseLength; return MasterScaffold( isDesktop: isDesktop, @@ -118,7 +119,7 @@ class _NewWalletRecoveryPhraseWarningViewState ); }, ), - ) + ), ], ), body: SingleChildScrollView( @@ -180,7 +181,8 @@ class _NewWalletRecoveryPhraseWarningViewState "access to your wallet.", style: isDesktop ? STextStyles.desktopTextMediumRegular( - context) + context, + ) : STextStyles.subtitle(context).copyWith( fontSize: 12, ), @@ -359,13 +361,14 @@ class _NewWalletRecoveryPhraseWarningViewState child: Text( "Do not show them to anyone.", style: STextStyles.navBarTitle( - context), + context, + ), ), ), ], ), ], - ) + ), ], ), ), @@ -410,12 +413,14 @@ class _NewWalletRecoveryPhraseWarningViewState MaterialTapTargetSize.shrinkWrap, value: ref .watch( - checkBoxStateProvider.state) + checkBoxStateProvider.state, + ) .state, onChanged: (newValue) { ref .read( - checkBoxStateProvider.state) + checkBoxStateProvider.state, + ) .state = newValue!; }, ), @@ -428,7 +433,8 @@ class _NewWalletRecoveryPhraseWarningViewState "I understand that Stack Wallet does not keep and cannot restore my recovery phrase, and If I lose my recovery phrase, I will not be able to access my funds.", style: isDesktop ? STextStyles.desktopTextMedium( - context) + context, + ) : STextStyles.baseXS(context) .copyWith( height: 1.3, @@ -452,21 +458,23 @@ class _NewWalletRecoveryPhraseWarningViewState .state ? () async { try { - unawaited(showDialog<dynamic>( - context: context, - barrierDismissible: false, - useSafeArea: true, - builder: (ctx) { - return const Center( - child: LoadingIndicator( - width: 50, - height: 50, - ), - ); - }, - )); + unawaited( + showDialog<dynamic>( + context: context, + barrierDismissible: false, + useSafeArea: true, + builder: (ctx) { + return const Center( + child: LoadingIndicator( + width: 50, + height: 50, + ), + ); + }, + ), + ); String? otherDataJsonString; - if (widget.coin == Coin.tezos) { + if (widget.coin is Tezos) { otherDataJsonString = jsonEncode({ WalletInfoKeys .tezosDerivationPath: @@ -474,7 +482,7 @@ class _NewWalletRecoveryPhraseWarningViewState .value, }); // }//todo: probably not needed (broken anyways) - // else if (widget.coin == Coin.epicCash) { + // else if (widget.coin is Epiccash) { // final int secondsSinceEpoch = // DateTime.now().millisecondsSinceEpoch ~/ 1000; // const int epicCashFirstBlock = 1565370278; @@ -504,8 +512,7 @@ class _NewWalletRecoveryPhraseWarningViewState // ), // }, // ); - } else if (widget.coin == - Coin.firo) { + } else if (widget.coin is Firo) { otherDataJsonString = jsonEncode( { WalletInfoKeys @@ -524,15 +531,18 @@ class _NewWalletRecoveryPhraseWarningViewState var node = ref .read( - nodeServiceChangeNotifierProvider) - .getPrimaryNodeFor(coin: coin); + nodeServiceChangeNotifierProvider, + ) + .getPrimaryNodeFor( + currency: coin, + ); if (node == null) { - node = - DefaultNodes.getNodeFor(coin); + node = coin.defaultNode; await ref .read( - nodeServiceChangeNotifierProvider) + nodeServiceChangeNotifierProvider, + ) .setPrimaryNodeFor( coin: coin, node: node, @@ -549,34 +559,35 @@ class _NewWalletRecoveryPhraseWarningViewState String? mnemonic; String? privateKey; - wordCount = Constants - .defaultSeedPhraseLengthFor( - coin: info.coin, - ); + wordCount = info + .coin.defaultSeedPhraseLength; - if (coin == Coin.monero || - coin == Coin.wownero) { + if (coin is Monero || + coin is Wownero) { // currently a special case due to the // xmr/wow libraries handling their // own mnemonic generation } else if (wordCount > 0) { if (ref - .read(pNewWalletOptions - .state) + .read( + pNewWalletOptions.state, + ) .state != null) { if (coin .hasMnemonicPassphraseSupport) { mnemonicPassphrase = ref - .read(pNewWalletOptions - .state) + .read( + pNewWalletOptions.state, + ) .state! .mnemonicPassphrase; } else {} wordCount = ref .read( - pNewWalletOptions.state) + pNewWalletOptions.state, + ) .state! .mnemonicWordsCount; } else { @@ -587,7 +598,8 @@ class _NewWalletRecoveryPhraseWarningViewState 24 < wordCount || wordCount % 3 != 0) { throw Exception( - "Invalid word count"); + "Invalid word count", + ); } final strength = @@ -604,9 +616,11 @@ class _NewWalletRecoveryPhraseWarningViewState secureStorageInterface: ref.read(secureStoreProvider), nodeService: ref.read( - nodeServiceChangeNotifierProvider), + nodeServiceChangeNotifierProvider, + ), prefs: ref.read( - prefsChangeNotifierProvider), + prefsChangeNotifierProvider, + ), mnemonicPassphrase: mnemonicPassphrase, mnemonic: mnemonic, @@ -616,31 +630,36 @@ class _NewWalletRecoveryPhraseWarningViewState await wallet.init(); // pop progress dialog - if (mounted) { + if (context.mounted) { Navigator.pop(context); } // set checkbox back to unchecked to annoy users to agree again :P ref .read( - checkBoxStateProvider.state) + checkBoxStateProvider.state, + ) .state = false; - if (mounted) { - unawaited(Navigator.of(context) - .pushNamed( - NewWalletRecoveryPhraseView - .routeName, - arguments: Tuple2( - wallet, - await (wallet - as MnemonicInterface) - .getMnemonicAsWords(), + if (context.mounted) { + final nav = Navigator.of(context); + unawaited( + nav.pushNamed( + NewWalletRecoveryPhraseView + .routeName, + arguments: Tuple2( + wallet, + await (wallet + as MnemonicInterface) + .getMnemonicAsWords(), + ), ), - )); + ); } } catch (e, s) { - Logging.instance.log("$e\n$s", - level: LogLevel.Fatal); + Logging.instance.log( + "$e\n$s", + level: LogLevel.Fatal, + ); // TODO: handle gracefully // any network/socket exception here will break new wallet creation rethrow; @@ -656,18 +675,22 @@ class _NewWalletRecoveryPhraseWarningViewState : Theme.of(context) .extension<StackColors>()! .getPrimaryDisabledButtonStyle( - context), + context, + ), child: Text( "View recovery phrase", style: isDesktop ? ref .read( - checkBoxStateProvider.state) + checkBoxStateProvider.state, + ) .state ? STextStyles.desktopButtonEnabled( - context) + context, + ) : STextStyles.desktopButtonDisabled( - context) + context, + ) : STextStyles.button(context), ), ), diff --git a/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/restore_options_view.dart b/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/restore_options_view.dart index 3c7bdfd9e..642833523 100644 --- a/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/restore_options_view.dart +++ b/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/restore_options_view.dart @@ -24,10 +24,13 @@ import 'package:stackwallet/providers/ui/verify_recovery_phrase/mnemonic_word_co import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/format.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/epiccash.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/monero.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/wownero.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/conditional_parent.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/date_picker/date_picker.dart'; @@ -48,7 +51,7 @@ class RestoreOptionsView extends ConsumerStatefulWidget { static const routeName = "/restoreOptions"; final String walletName; - final Coin coin; + final CryptoCurrency coin; @override ConsumerState<RestoreOptionsView> createState() => _RestoreOptionsViewState(); @@ -56,7 +59,7 @@ class RestoreOptionsView extends ConsumerStatefulWidget { class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> { late final String walletName; - late final Coin coin; + late final CryptoCurrency coin; late final bool isDesktop; late TextEditingController _dateController; @@ -69,8 +72,7 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> { bool hidePassword = true; bool _expandedAdavnced = false; - bool get supportsMnemonicPassphrase => - !(coin == Coin.monero || coin == Coin.wownero || coin == Coin.epicCash); + bool get supportsMnemonicPassphrase => coin.hasMnemonicPassphraseSupport; @override void initState() { @@ -153,7 +155,7 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> { ), builder: (_) { return MnemonicWordCountSelectSheet( - lengthOptions: Constants.possibleLengthsForCoin(coin), + lengthOptions: coin.possibleMnemonicLengths, ); }, ); @@ -161,9 +163,9 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> { @override Widget build(BuildContext context) { - debugPrint("BUILD: $runtimeType with ${coin.name} $walletName"); + debugPrint("BUILD: $runtimeType with ${coin.identifier} $walletName"); - final lengths = Constants.possibleLengthsForCoin(coin).toList(); + final lengths = coin.possibleMnemonicLengths; return MasterScaffold( isDesktop: isDesktop, @@ -217,9 +219,9 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> { SizedBox( height: isDesktop ? 40 : 24, ), - if (coin == Coin.monero || - coin == Coin.epicCash || - (coin == Coin.wownero && + if (coin is Monero || + coin is Epiccash || + (coin is Wownero && ref.watch(mnemonicWordCountStateProvider.state).state == 25)) Text( @@ -233,17 +235,17 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> { : STextStyles.smallMed12(context), textAlign: TextAlign.left, ), - if (coin == Coin.monero || - coin == Coin.epicCash || - (coin == Coin.wownero && + if (coin is Monero || + coin is Epiccash || + (coin is Wownero && ref.watch(mnemonicWordCountStateProvider.state).state == 25)) SizedBox( height: isDesktop ? 16 : 8, ), - if (coin == Coin.monero || - coin == Coin.epicCash || - (coin == Coin.wownero && + if (coin is Monero || + coin is Epiccash || + (coin is Wownero && ref.watch(mnemonicWordCountStateProvider.state).state == 25)) if (!isDesktop) @@ -251,9 +253,9 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> { onTap: chooseDate, controller: _dateController, ), - if (coin == Coin.monero || - coin == Coin.epicCash || - (coin == Coin.wownero && + if (coin is Monero || + coin is Epiccash || + (coin is Wownero && ref.watch(mnemonicWordCountStateProvider.state).state == 25)) if (isDesktop) @@ -262,17 +264,17 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> { onTap: chooseDesktopDate, controller: _dateController, ), - if (coin == Coin.monero || - coin == Coin.epicCash || - (coin == Coin.wownero && + if (coin is Monero || + coin is Epiccash || + (coin is Wownero && ref.watch(mnemonicWordCountStateProvider.state).state == 25)) const SizedBox( height: 8, ), - if (coin == Coin.monero || - coin == Coin.epicCash || - (coin == Coin.wownero && + if (coin is Monero || + coin is Epiccash || + (coin is Wownero && ref.watch(mnemonicWordCountStateProvider.state).state == 25)) RoundedWhiteContainer( @@ -291,9 +293,9 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> { ), ), ), - if (coin == Coin.monero || - coin == Coin.epicCash || - (coin == Coin.wownero && + if (coin is Monero || + coin is Epiccash || + (coin is Wownero && ref.watch(mnemonicWordCountStateProvider.state).state == 25)) SizedBox( 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 14174b22b..1b07eb565 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 @@ -18,8 +18,8 @@ import 'package:bip39/bip39.dart' as bip39; import 'package:bip39/src/wordlists/english.dart' as bip39wordlist; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter_libmonero/monero/monero.dart'; -import 'package:flutter_libmonero/wownero/wownero.dart'; +import 'package:flutter_libmonero/monero/monero.dart' as libxmr; +import 'package:flutter_libmonero/wownero/wownero.dart' as libwow; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:stackwallet/notifications/show_flush_bar.dart'; @@ -44,12 +44,16 @@ import 'package:stackwallet/utilities/barcode_scanner_interface.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/custom_text_selection_controls.dart'; -import 'package:stackwallet/utilities/default_nodes.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/form_input_status_enum.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/epiccash.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/ethereum.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/monero.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/wownero.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/isar/models/wallet_info.dart'; import 'package:stackwallet/wallets/wallet/impl/epiccash_wallet.dart'; import 'package:stackwallet/wallets/wallet/impl/monero_wallet.dart'; @@ -69,7 +73,7 @@ import 'package:wakelock/wakelock.dart'; class RestoreWalletView extends ConsumerStatefulWidget { const RestoreWalletView({ - Key? key, + super.key, required this.walletName, required this.coin, required this.seedWordsLength, @@ -77,12 +81,12 @@ class RestoreWalletView extends ConsumerStatefulWidget { required this.restoreFromDate, this.barcodeScanner = const BarcodeScannerWrapper(), this.clipboard = const ClipboardWrapper(), - }) : super(key: key); + }); static const routeName = "/restoreWallet"; final String walletName; - final Coin coin; + final CryptoCurrency coin; final String mnemonicPassphrase; final int seedWordsLength; final DateTime restoreFromDate; @@ -166,7 +170,7 @@ class _RestoreWalletViewState extends ConsumerState<RestoreWalletView> { @override void dispose() { - for (var element in _controllers) { + for (final element in _controllers) { element.dispose(); } @@ -176,13 +180,15 @@ class _RestoreWalletViewState extends ConsumerState<RestoreWalletView> { // TODO: check for wownero wordlist? bool _isValidMnemonicWord(String word) { // TODO: get the actual language - if (widget.coin == Coin.monero) { - var moneroWordList = monero.getMoneroWordList("English"); + if (widget.coin is Monero) { + final moneroWordList = libxmr.monero.getMoneroWordList("English"); return moneroWordList.contains(word); } - if (widget.coin == Coin.wownero) { - var wowneroWordList = wownero.getWowneroWordList("English", - seedWordsLength: widget.seedWordsLength); + if (widget.coin is Wownero) { + final wowneroWordList = libwow.wownero.getWowneroWordList( + "English", + seedWordsLength: widget.seedWordsLength, + ); return wowneroWordList.contains(word); } return _wordListHashSet.contains(word); @@ -201,7 +207,7 @@ class _RestoreWalletViewState extends ConsumerState<RestoreWalletView> { Future<void> attemptRestore() async { if (_formKey.currentState!.validate()) { String mnemonic = ""; - for (var element in _controllers) { + for (final element in _controllers) { mnemonic += " ${element.text.trim().toLowerCase()}"; } mnemonic = mnemonic.trim(); @@ -209,24 +215,25 @@ class _RestoreWalletViewState extends ConsumerState<RestoreWalletView> { int height = 0; String? otherDataJsonString; - if (widget.coin == Coin.monero) { - height = monero.getHeigthByDate(date: widget.restoreFromDate); - } else if (widget.coin == Coin.wownero) { - height = wownero.getHeightByDate(date: widget.restoreFromDate); + if (widget.coin is Monero) { + height = libxmr.monero.getHeigthByDate(date: widget.restoreFromDate); + } else if (widget.coin is Wownero) { + height = libwow.wownero.getHeightByDate(date: widget.restoreFromDate); } // todo: wait until this implemented - // else if (widget.coin == Coin.wownero) { + // else if (widget.coin is Wownero) { // height = wownero.getHeightByDate(date: widget.restoreFromDate); // } // TODO: make more robust estimate of date maybe using https://explorer.epic.tech/api-index - if (widget.coin == Coin.epicCash) { - int secondsSinceEpoch = + if (widget.coin is Epiccash) { + final int secondsSinceEpoch = widget.restoreFromDate.millisecondsSinceEpoch ~/ 1000; const int epicCashFirstBlock = 1565370278; const double overestimateSecondsPerBlock = 61; - int chosenSeconds = secondsSinceEpoch - epicCashFirstBlock; - int approximateHeight = chosenSeconds ~/ overestimateSecondsPerBlock; + final int chosenSeconds = secondsSinceEpoch - epicCashFirstBlock; + final int approximateHeight = + chosenSeconds ~/ overestimateSecondsPerBlock; //todo: check if print needed // debugPrint( // "approximate height: $approximateHeight chosen_seconds: $chosenSeconds"); @@ -250,7 +257,7 @@ class _RestoreWalletViewState extends ConsumerState<RestoreWalletView> { ), }, ); - } else if (widget.coin == Coin.firo) { + } else if (widget.coin is Firo) { otherDataJsonString = jsonEncode( { WalletInfoKeys.lelantusCoinIsarRescanRequired: false, @@ -260,12 +267,14 @@ class _RestoreWalletViewState extends ConsumerState<RestoreWalletView> { // TODO: do actual check to make sure it is a valid mnemonic for monero if (bip39.validateMnemonic(mnemonic) == false && - !(widget.coin == Coin.monero || widget.coin == Coin.wownero)) { - unawaited(showFloatingFlushBar( - type: FlushBarType.warning, - message: "Invalid seed phrase!", - context: context, - )); + !(widget.coin is Monero || widget.coin is Wownero)) { + unawaited( + showFloatingFlushBar( + type: FlushBarType.warning, + message: "Invalid seed phrase!", + context: context, + ), + ); } else { if (!Platform.isLinux) await Wakelock.enable(); @@ -278,30 +287,35 @@ class _RestoreWalletViewState extends ConsumerState<RestoreWalletView> { bool isRestoring = true; // show restoring in progress - unawaited(showDialog<dynamic>( - context: context, - useSafeArea: false, - barrierDismissible: false, - builder: (context) { - return RestoringDialog( - onCancel: () async { - isRestoring = false; - await ref.read(pWallets).deleteWallet( - info, - ref.read(secureStoreProvider), - ); + if (mounted) { + unawaited( + showDialog<dynamic>( + context: context, + useSafeArea: false, + barrierDismissible: false, + builder: (context) { + return RestoringDialog( + onCancel: () async { + isRestoring = false; + + await ref.read(pWallets).deleteWallet( + info, + ref.read(secureStoreProvider), + ); + }, + ); }, - ); - }, - )); + ), + ); + } var node = ref .read(nodeServiceChangeNotifierProvider) - .getPrimaryNodeFor(coin: widget.coin); + .getPrimaryNodeFor(currency: widget.coin); if (node == null) { - node = DefaultNodes.getNodeFor(widget.coin); + node = widget.coin.defaultNode; await ref.read(nodeServiceChangeNotifierProvider).setPrimaryNodeFor( coin: widget.coin, node: node, @@ -324,15 +338,15 @@ class _RestoreWalletViewState extends ConsumerState<RestoreWalletView> { // TODO: extract interface with isRestore param switch (wallet.runtimeType) { - case EpiccashWallet: + case const (EpiccashWallet): await (wallet as EpiccashWallet).init(isRestore: true); break; - case MoneroWallet: + case const (MoneroWallet): await (wallet as MoneroWallet).init(isRestore: true); break; - case WowneroWallet: + case const (WowneroWallet): await (wallet as WowneroWallet).init(isRestore: true); break; @@ -355,12 +369,11 @@ class _RestoreWalletViewState extends ConsumerState<RestoreWalletView> { if (isCreateSpecialEthWallet) { ref.read(createSpecialEthWalletRoutingFlag.notifier).state = false; - ref - .read(newEthWalletTriggerTempUntilHiveCompletelyDeleted.state) - .state = + ref.read(newEthWalletTriggerTempUntilHiveCompletelyDeleted.state).state = !ref - .read(newEthWalletTriggerTempUntilHiveCompletelyDeleted - .state) + .read( + newEthWalletTriggerTempUntilHiveCompletelyDeleted.state, + ) .state; } @@ -385,7 +398,7 @@ class _RestoreWalletViewState extends ConsumerState<RestoreWalletView> { (route) => false, ), ); - if (info.coin == Coin.ethereum) { + if (info.coin is Ethereum) { unawaited( Navigator.of(context).pushNamed( EditWalletTokensView.routeName, @@ -451,7 +464,9 @@ class _RestoreWalletViewState extends ConsumerState<RestoreWalletView> { } InputDecoration _getInputDecorationFor( - FormInputStatus status, String prefix) { + FormInputStatus status, + String prefix, + ) { Color color; Color prefixColor; Color borderColor; @@ -656,9 +671,10 @@ class _RestoreWalletViewState extends ConsumerState<RestoreWalletView> { if (FocusScope.of(context).hasFocus) { FocusScope.of(context).unfocus(); await Future<void>.delayed( - const Duration(milliseconds: 50)); + const Duration(milliseconds: 50), + ); } - if (mounted) { + if (context.mounted) { Navigator.of(context).pop(); } }, @@ -788,8 +804,9 @@ class _RestoreWalletViewState extends ConsumerState<RestoreWalletView> { "Paste", style: STextStyles .desktopButtonSmallSecondaryEnabled( - context), - ) + context, + ), + ), ], ), ), @@ -836,12 +853,14 @@ class _RestoreWalletViewState extends ConsumerState<RestoreWalletView> { textCapitalization: TextCapitalization.none, key: Key( - "restoreMnemonicFormField_$i"), + "restoreMnemonicFormField_$i", + ), decoration: _getInputDecorationFor( - _inputStatuses[ - i * 4 + j - 1], - "${i * 4 + j}"), + _inputStatuses[ + i * 4 + j - 1], + "${i * 4 + j}", + ), autovalidateMode: AutovalidateMode .onUserInteraction, @@ -861,9 +880,10 @@ class _RestoreWalletViewState extends ConsumerState<RestoreWalletView> { formInputStatus = FormInputStatus.empty; } else if (_isValidMnemonicWord( - value - .trim() - .toLowerCase())) { + value + .trim() + .toLowerCase(), + )) { formInputStatus = FormInputStatus.valid; } else { @@ -921,17 +941,18 @@ class _RestoreWalletViewState extends ConsumerState<RestoreWalletView> { TextAlign.left, style: STextStyles.label( - context) - .copyWith( + context, + ).copyWith( color: Theme.of( - context) + context, + ) .extension< StackColors>()! .textError, ), ), ), - ) + ), ], ), ), @@ -945,7 +966,7 @@ class _RestoreWalletViewState extends ConsumerState<RestoreWalletView> { for (int i = rows * cols; i < _seedWordCount - remainder; i++) ...[ - TableViewCell( + const TableViewCell( flex: 1, child: Column( // ... (existing code for input field) @@ -965,11 +986,13 @@ class _RestoreWalletViewState extends ConsumerState<RestoreWalletView> { textCapitalization: TextCapitalization.none, key: Key( - "restoreMnemonicFormField_$i"), + "restoreMnemonicFormField_$i", + ), decoration: _getInputDecorationFor( - _inputStatuses[i], - "${i + 1}"), + _inputStatuses[i], + "${i + 1}", + ), autovalidateMode: AutovalidateMode .onUserInteraction, @@ -984,9 +1007,10 @@ class _RestoreWalletViewState extends ConsumerState<RestoreWalletView> { formInputStatus = FormInputStatus.empty; } else if (_isValidMnemonicWord( - value - .trim() - .toLowerCase())) { + value + .trim() + .toLowerCase(), + )) { formInputStatus = FormInputStatus.valid; } else { @@ -1029,17 +1053,18 @@ class _RestoreWalletViewState extends ConsumerState<RestoreWalletView> { TextAlign.left, style: STextStyles.label( - context) - .copyWith( + context, + ).copyWith( color: Theme.of( - context) + context, + ) .extension< StackColors>()! .textError, ), ), ), - ) + ), ], ), ), @@ -1095,7 +1120,9 @@ class _RestoreWalletViewState extends ConsumerState<RestoreWalletView> { textCapitalization: TextCapitalization.none, key: Key("restoreMnemonicFormField_$i"), decoration: _getInputDecorationFor( - _inputStatuses[i - 1], "$i"), + _inputStatuses[i - 1], + "$i", + ), autovalidateMode: AutovalidateMode.onUserInteraction, selectionControls: @@ -1107,7 +1134,8 @@ class _RestoreWalletViewState extends ConsumerState<RestoreWalletView> { if (value.isEmpty) { formInputStatus = FormInputStatus.empty; } else if (_isValidMnemonicWord( - value.trim().toLowerCase())) { + value.trim().toLowerCase(), + )) { formInputStatus = FormInputStatus.valid; } else { formInputStatus = @@ -1155,7 +1183,7 @@ class _RestoreWalletViewState extends ConsumerState<RestoreWalletView> { ), ), ), - ) + ), ], ), Padding( diff --git a/lib/pages/add_wallet_views/select_wallet_for_token_view.dart b/lib/pages/add_wallet_views/select_wallet_for_token_view.dart index d0f466a0c..ecffeaaaf 100644 --- a/lib/pages/add_wallet_views/select_wallet_for_token_view.dart +++ b/lib/pages/add_wallet_views/select_wallet_for_token_view.dart @@ -70,7 +70,7 @@ class _SelectWalletForTokenViewState ref.read(createSpecialEthWalletRoutingFlag.notifier).state = true; Navigator.of(context).pushNamed( CreateOrRestoreWalletView.routeName, - arguments: CoinEntity(widget.entity.coin), + arguments: CoinEntity(widget.entity.cryptoCurrency), ); } @@ -78,7 +78,7 @@ class _SelectWalletForTokenViewState Widget build(BuildContext context) { final ethWalletInfos = ref .watch(pAllWalletsInfo) - .where((e) => e.coin == widget.entity.coin) + .where((e) => e.coin == widget.entity.cryptoCurrency) .toList(); final _hasEthWallets = ethWalletInfos.isNotEmpty; diff --git a/lib/pages/add_wallet_views/verify_recovery_phrase_view/verify_recovery_phrase_view.dart b/lib/pages/add_wallet_views/verify_recovery_phrase_view/verify_recovery_phrase_view.dart index 90163db3f..3443c2084 100644 --- a/lib/pages/add_wallet_views/verify_recovery_phrase_view/verify_recovery_phrase_view.dart +++ b/lib/pages/add_wallet_views/verify_recovery_phrase_view/verify_recovery_phrase_view.dart @@ -30,9 +30,9 @@ import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/ethereum.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; import 'package:stackwallet/wallets/wallet/wallet.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; @@ -44,10 +44,10 @@ final createSpecialEthWalletRoutingFlag = StateProvider((ref) => false); class VerifyRecoveryPhraseView extends ConsumerStatefulWidget { const VerifyRecoveryPhraseView({ - Key? key, + super.key, required this.wallet, required this.mnemonic, - }) : super(key: key); + }); static const routeName = "/verifyRecoveryPhrase"; @@ -154,7 +154,7 @@ class _VerifyRecoveryPhraseViewState DesktopHomeView.routeName, ), ); - if (widget.wallet.info.coin == Coin.ethereum) { + if (widget.wallet.info.coin is Ethereum) { unawaited( Navigator.of(context).pushNamed( EditWalletTokensView.routeName, @@ -177,7 +177,7 @@ class _VerifyRecoveryPhraseViewState (route) => false, ), ); - if (widget.wallet.info.coin == Coin.ethereum) { + if (widget.wallet.info.coin is Ethereum) { unawaited( Navigator.of(context).pushNamed( EditWalletTokensView.routeName, @@ -198,12 +198,14 @@ class _VerifyRecoveryPhraseViewState ); } } else { - unawaited(showFloatingFlushBar( - type: FlushBarType.warning, - message: "Incorrect. Please try again.", - iconAsset: Assets.svg.circleX, - context: context, - )); + unawaited( + showFloatingFlushBar( + type: FlushBarType.warning, + message: "Incorrect. Please try again.", + iconAsset: Assets.svg.circleX, + context: context, + ), + ); final int next = Random().nextInt(_mnemonic.length); ref @@ -221,7 +223,10 @@ class _VerifyRecoveryPhraseViewState } Tuple2<List<String>, String> randomize( - List<String> mnemonic, int chosenIndex, int wordsToShow) { + List<String> mnemonic, + int chosenIndex, + int wordsToShow, + ) { final List<String> remaining = []; final String chosenWord = mnemonic[chosenIndex]; @@ -354,7 +359,8 @@ class _VerifyRecoveryPhraseViewState .extension<StackColors>()! .textFieldDefaultBG, borderRadius: BorderRadius.circular( - Constants.size.circularBorderRadius), + Constants.size.circularBorderRadius, + ), ), child: Padding( padding: const EdgeInsets.symmetric( @@ -391,11 +397,13 @@ class _VerifyRecoveryPhraseViewState builder: (_, ref, __) { final selectedWord = ref .watch( - verifyMnemonicSelectedWordStateProvider.state) + verifyMnemonicSelectedWordStateProvider.state, + ) .state; final correctWord = ref .watch( - verifyMnemonicCorrectWordStateProvider.state) + verifyMnemonicCorrectWordStateProvider.state, + ) .state; return ConstrainedBox( @@ -406,7 +414,8 @@ class _VerifyRecoveryPhraseViewState onPressed: selectedWord.isNotEmpty ? () async { await _continue( - correctWord == selectedWord); + correctWord == selectedWord, + ); } : null, style: selectedWord.isNotEmpty @@ -421,9 +430,11 @@ class _VerifyRecoveryPhraseViewState "Verify", style: selectedWord.isNotEmpty ? STextStyles.desktopButtonEnabled( - context) + context, + ) : STextStyles.desktopButtonDisabled( - context), + context, + ), ) : Text( "Continue", diff --git a/lib/pages/address_book_views/address_book_view.dart b/lib/pages/address_book_views/address_book_view.dart index 61d6233bd..3f47a8cd7 100644 --- a/lib/pages/address_book_views/address_book_view.dart +++ b/lib/pages/address_book_views/address_book_view.dart @@ -20,12 +20,14 @@ import 'package:stackwallet/providers/db/main_db_provider.dart'; import 'package:stackwallet/providers/global/address_book_service_provider.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/ui/address_book_providers/address_book_filter_provider.dart'; +import 'package:stackwallet/supported_coins.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/spark_interface.dart'; import 'package:stackwallet/widgets/address_book_card.dart'; import 'package:stackwallet/widgets/background.dart'; @@ -45,7 +47,7 @@ class AddressBookView extends ConsumerStatefulWidget { static const String routeName = "/addressBook"; - final Coin? coin; + final CryptoCurrency? coin; final String? filterTerm; @override @@ -65,8 +67,10 @@ class _AddressBookViewState extends ConsumerState<AddressBookView> { ref.refresh(addressBookFilterProvider); if (widget.coin == null) { - final List<Coin> coins = Coin.values.toList(); - coins.remove(Coin.firoTestNet); + final coins = [...SupportedCoins.cryptocurrencies]; + coins.removeWhere( + (e) => e is Firo && e.network == CryptoCurrencyNetwork.test, + ); final bool showTestNet = ref.read(prefsChangeNotifierProvider).showTestNetCoins; @@ -74,9 +78,10 @@ class _AddressBookViewState extends ConsumerState<AddressBookView> { if (showTestNet) { ref.read(addressBookFilterProvider).addAll(coins, false); } else { - ref - .read(addressBookFilterProvider) - .addAll(coins.where((e) => !e.isTestNet), false); + ref.read(addressBookFilterProvider).addAll( + coins.where((e) => e.network != CryptoCurrencyNetwork.test), + false, + ); } } else { ref.read(addressBookFilterProvider).add(widget.coin!, false); @@ -101,7 +106,7 @@ class _AddressBookViewState extends ConsumerState<AddressBookView> { addresses.add( ContactAddressEntry() - ..coinName = wallet.info.coin.name + ..coinName = wallet.info.coin.identifier ..address = addressString ..label = "Current Receiving" ..other = wallet.info.name, diff --git a/lib/pages/address_book_views/subviews/address_book_filter_view.dart b/lib/pages/address_book_views/subviews/address_book_filter_view.dart index 64eb97552..d973555af 100644 --- a/lib/pages/address_book_views/subviews/address_book_filter_view.dart +++ b/lib/pages/address_book_views/subviews/address_book_filter_view.dart @@ -12,10 +12,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/providers/global/prefs_provider.dart'; import 'package:stackwallet/providers/ui/address_book_providers/address_book_filter_provider.dart'; +import 'package:stackwallet/supported_coins.dart'; import 'package:stackwallet/themes/stack_colors.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/background.dart'; import 'package:stackwallet/widgets/conditional_parent.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; @@ -25,7 +27,7 @@ import 'package:stackwallet/widgets/desktop/secondary_button.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; class AddressBookFilterView extends ConsumerStatefulWidget { - const AddressBookFilterView({Key? key}) : super(key: key); + const AddressBookFilterView({super.key}); static const String routeName = "/addressBookFilter"; @@ -35,19 +37,23 @@ class AddressBookFilterView extends ConsumerStatefulWidget { } class _AddressBookFilterViewState extends ConsumerState<AddressBookFilterView> { - late final List<Coin> _coins; + late final List<CryptoCurrency> _coins; @override void initState() { - List<Coin> coins = [...Coin.values]; - coins.remove(Coin.firoTestNet); + final coins = [...SupportedCoins.cryptocurrencies]; + coins.removeWhere( + (e) => e is Firo && e.network == CryptoCurrencyNetwork.test, + ); - bool showTestNet = ref.read(prefsChangeNotifierProvider).showTestNetCoins; + final showTestNet = ref.read(prefsChangeNotifierProvider).showTestNetCoins; if (showTestNet) { _coins = coins.toList(growable: false); } else { - _coins = coins.where((e) => !e.isTestNet).toList(growable: false); + _coins = coins + .where((e) => e.network != CryptoCurrencyNetwork.test) + .toList(growable: false); } super.initState(); } diff --git a/lib/pages/address_book_views/subviews/coin_select_sheet.dart b/lib/pages/address_book_views/subviews/coin_select_sheet.dart index 922502abd..fe8b91af5 100644 --- a/lib/pages/address_book_views/subviews/coin_select_sheet.dart +++ b/lib/pages/address_book_views/subviews/coin_select_sheet.dart @@ -14,20 +14,24 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/providers/global/prefs_provider.dart'; +import 'package:stackwallet/supported_coins.dart'; import 'package:stackwallet/themes/coin_image_provider.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; class CoinSelectSheet extends StatelessWidget { - const CoinSelectSheet({Key? key}) : super(key: key); + const CoinSelectSheet({super.key}); @override Widget build(BuildContext context) { final maxHeight = MediaQuery.of(context).size.height * 0.60; - var coins_ = [...Coin.values]; - coins_.remove(Coin.firoTestNet); + final coins_ = [...SupportedCoins.cryptocurrencies]; + coins_.removeWhere( + (e) => e is Firo && e.network == CryptoCurrencyNetwork.test, + ); return Container( decoration: BoxDecoration( color: Theme.of(context).extension<StackColors>()!.popupBG, @@ -85,7 +89,11 @@ class CoinSelectSheet extends StatelessWidget { shrinkWrap: true, itemCount: showTestNet ? coins_.length - : coins_.where((e) => !e.isTestNet).length, + : coins_ + .where( + (e) => e.network != CryptoCurrencyNetwork.test, + ) + .length, itemBuilder: (builderContext, index) { final coin = coins_[index]; return Padding( diff --git a/lib/pages/address_book_views/subviews/contact_details_view.dart b/lib/pages/address_book_views/subviews/contact_details_view.dart index 419081f2b..d01cd2335 100644 --- a/lib/pages/address_book_views/subviews/contact_details_view.dart +++ b/lib/pages/address_book_views/subviews/contact_details_view.dart @@ -27,7 +27,6 @@ import 'package:stackwallet/themes/coin_icon_provider.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/widgets/background.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; @@ -41,10 +40,10 @@ import 'package:tuple/tuple.dart'; class ContactDetailsView extends ConsumerStatefulWidget { const ContactDetailsView({ - Key? key, + super.key, required this.contactId, this.clipboard = const ClipboardWrapper(), - }) : super(key: key); + }); static const String routeName = "/contactDetails"; @@ -79,7 +78,7 @@ class _ContactDetailsViewState extends ConsumerState<ContactDetailsView> { .sortByTimestampDesc() .findAll(); - List<Tuple2<String, Transaction>> result = []; + final List<Tuple2<String, Transaction>> result = []; for (final tx in transactions) { result.add(Tuple2(tx.walletId, tx)); @@ -151,7 +150,7 @@ class _ContactDetailsViewState extends ConsumerState<ContactDetailsView> { height: 20, ), onPressed: () { - bool isFavorite = _contact.isFavorite; + final bool isFavorite = _contact.isFavorite; ref.read(addressBookServiceProvider).editContact( _contact.copyWith(isFavorite: !isFavorite)); diff --git a/lib/pages/address_book_views/subviews/contact_popup.dart b/lib/pages/address_book_views/subviews/contact_popup.dart index ae31f8c09..a22b205aa 100644 --- a/lib/pages/address_book_views/subviews/contact_popup.dart +++ b/lib/pages/address_book_views/subviews/contact_popup.dart @@ -27,7 +27,6 @@ import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/themes/theme_providers.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; @@ -56,8 +55,8 @@ class ContactPopUp extends ConsumerWidget { final active = ref.read(currentWalletIdProvider); - bool hasActiveWallet = active != null; - bool isExchangeFlow = + final bool hasActiveWallet = active != null; + final bool isExchangeFlow = ref.watch(exchangeFlowIsActiveStateProvider.state).state; final addresses = contact.addressesSorted.where((e) { diff --git a/lib/pages/address_book_views/subviews/new_contact_address_entry_form.dart b/lib/pages/address_book_views/subviews/new_contact_address_entry_form.dart index 7381de7cc..00a735c93 100644 --- a/lib/pages/address_book_views/subviews/new_contact_address_entry_form.dart +++ b/lib/pages/address_book_views/subviews/new_contact_address_entry_form.dart @@ -19,6 +19,7 @@ import 'package:stackwallet/pages/address_book_views/subviews/coin_select_sheet. import 'package:stackwallet/providers/providers.dart'; // import 'package:stackwallet/providers/global/should_show_lockscreen_on_resume_state_provider.dart'; import 'package:stackwallet/providers/ui/address_book_providers/address_entry_data_provider.dart'; +import 'package:stackwallet/supported_coins.dart'; import 'package:stackwallet/themes/coin_icon_provider.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/address_utils.dart'; @@ -26,10 +27,11 @@ import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/barcode_scanner_interface.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.dart'; import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart'; import 'package:stackwallet/widgets/icon_widgets/x_icon.dart'; @@ -62,7 +64,7 @@ class _NewContactAddressEntryFormState late final FocusNode addressLabelFocusNode; late final FocusNode addressFocusNode; - List<Coin> coins = []; + List<CryptoCurrency> coins = []; @override void initState() { @@ -72,7 +74,7 @@ class _NewContactAddressEntryFormState ..text = ref.read(addressEntryDataProvider(widget.id)).address ?? ""; addressLabelFocusNode = FocusNode(); addressFocusNode = FocusNode(); - coins = [...Coin.values]; + coins = [...SupportedCoins.cryptocurrencies]; super.initState(); } @@ -88,15 +90,20 @@ class _NewContactAddressEntryFormState @override Widget build(BuildContext context) { final isDesktop = Util.isDesktop; - bool showTestNet = ref.watch( - prefsChangeNotifierProvider.select((value) => value.showTestNetCoins), - ); if (isDesktop) { - coins = [...Coin.values]; + coins = [...SupportedCoins.cryptocurrencies]; + coins.removeWhere( + (e) => e is Firo && e.network == CryptoCurrencyNetwork.test, + ); - coins.remove(Coin.firoTestNet); + final showTestNet = + ref.read(prefsChangeNotifierProvider).showTestNetCoins; if (showTestNet) { - coins = coins.where((e) => !e.isTestNet).toList(); + coins = coins.toList(); + } else { + coins = coins + .where((e) => e.network != CryptoCurrencyNetwork.test) + .toList(); } } @@ -104,7 +111,7 @@ class _NewContactAddressEntryFormState children: [ if (isDesktop) DropdownButtonHideUnderline( - child: DropdownButton2<Coin>( + child: DropdownButton2<CryptoCurrency>( hint: Text( "Select cryptocurrency", style: STextStyles.fieldLabel(context), @@ -128,10 +135,12 @@ class _NewContactAddressEntryFormState ), ), isExpanded: true, - value: ref.watch(addressEntryDataProvider(widget.id) - .select((value) => value.coin)), + value: ref.watch( + addressEntryDataProvider(widget.id) + .select((value) => value.coin), + ), onChanged: (value) { - if (value is Coin) { + if (value is CryptoCurrency) { ref.read(addressEntryDataProvider(widget.id)).coin = value; } }, @@ -145,7 +154,7 @@ class _NewContactAddressEntryFormState ), items: [ ...coins.map( - (coin) => DropdownMenuItem<Coin>( + (coin) => DropdownMenuItem<CryptoCurrency>( value: coin, child: Padding( padding: const EdgeInsets.symmetric(vertical: 4), @@ -205,7 +214,7 @@ class _NewContactAddressEntryFormState context: context, builder: (_) => const CoinSelectSheet(), ).then((value) { - if (value is Coin) { + if (value is CryptoCurrency) { ref.read(addressEntryDataProvider(widget.id)).coin = value; } @@ -214,8 +223,10 @@ class _NewContactAddressEntryFormState child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - ref.watch(addressEntryDataProvider(widget.id) - .select((value) => value.coin)) == + ref.watch( + addressEntryDataProvider(widget.id) + .select((value) => value.coin), + ) == null ? Text( "Select cryptocurrency", @@ -245,8 +256,9 @@ class _NewContactAddressEntryFormState Text( ref .watch( - addressEntryDataProvider(widget.id) - .select((value) => value.coin))! + addressEntryDataProvider(widget.id) + .select((value) => value.coin), + )! .prettyName, style: STextStyles.itemSubtitle12(context), ), @@ -335,8 +347,10 @@ class _NewContactAddressEntryFormState suffixIcon: UnconstrainedBox( child: Row( children: [ - if (ref.watch(addressEntryDataProvider(widget.id) - .select((value) => value.address)) != + if (ref.watch( + addressEntryDataProvider(widget.id) + .select((value) => value.address), + ) != null) TextFieldIconButton( key: const Key("addAddressBookClearAddressButtonKey"), @@ -348,8 +362,10 @@ class _NewContactAddressEntryFormState }, child: const XIcon(), ), - if (ref.watch(addressEntryDataProvider(widget.id) - .select((value) => value.address)) == + if (ref.watch( + addressEntryDataProvider(widget.id) + .select((value) => value.address), + ) == null) TextFieldIconButton( key: const Key("addAddressPasteAddressButtonKey"), @@ -372,8 +388,10 @@ class _NewContactAddressEntryFormState child: const ClipboardIcon(), ), if (!Util.isDesktop && - ref.watch(addressEntryDataProvider(widget.id) - .select((value) => value.address)) == + ref.watch( + addressEntryDataProvider(widget.id) + .select((value) => value.address), + ) == null) TextFieldIconButton( key: const Key("addAddressBookEntryScanQrButtonKey"), @@ -419,11 +437,12 @@ class _NewContactAddressEntryFormState .read(addressEntryDataProvider(widget.id)) .coin != null) { - if (AddressUtils.validateAddress( - qrResult.rawContent, - ref - .read(addressEntryDataProvider(widget.id)) - .coin!)) { + if (ref + .read(addressEntryDataProvider(widget.id)) + .coin! + .validateAddress( + qrResult.rawContent, + )) { addressController.text = qrResult.rawContent; ref .read(addressEntryDataProvider(widget.id)) @@ -436,8 +455,9 @@ class _NewContactAddressEntryFormState // .state) // .state = true; Logging.instance.log( - "Failed to get camera permissions to scan address qr code: $e\n$s", - level: LogLevel.Warning); + "Failed to get camera permissions to scan address qr code: $e\n$s", + level: LogLevel.Warning, + ); } }, child: const QrCodeIcon(), @@ -466,8 +486,10 @@ class _NewContactAddressEntryFormState }, ), ), - if (!ref.watch(addressEntryDataProvider(widget.id) - .select((value) => value.isValidAddress)) && + if (!ref.watch( + addressEntryDataProvider(widget.id) + .select((value) => value.isValidAddress), + ) && addressController.text.isNotEmpty) Row( children: [ diff --git a/lib/pages/buy_view/buy_form.dart b/lib/pages/buy_view/buy_form.dart index d986a1e3c..67021d8f8 100644 --- a/lib/pages/buy_view/buy_form.dart +++ b/lib/pages/buy_view/buy_form.dart @@ -30,16 +30,17 @@ import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/services/buy/buy_response.dart'; import 'package:stackwallet/services/buy/simplex/simplex_api.dart'; +import 'package:stackwallet/supported_coins.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/address_utils.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/barcode_scanner_interface.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/conditional_parent.dart'; import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart'; import 'package:stackwallet/widgets/custom_loading_overlay.dart'; @@ -58,14 +59,14 @@ import 'package:stackwallet/widgets/textfield_icon_button.dart'; class BuyForm extends ConsumerStatefulWidget { const BuyForm({ - Key? key, + super.key, this.coin, this.tokenContract, this.clipboard = const ClipboardWrapper(), this.scanner = const BarcodeScannerWrapper(), - }) : super(key: key); + }); - final Coin? coin; + final CryptoCurrency? coin; final ClipboardInterface clipboard; final BarcodeScannerInterface scanner; @@ -76,7 +77,7 @@ class BuyForm extends ConsumerStatefulWidget { } class _BuyFormState extends ConsumerState<BuyForm> { - late final Coin? coin; + late final CryptoCurrency? coin; late final ClipboardInterface clipboard; late final BarcodeScannerInterface scanner; @@ -249,7 +250,8 @@ class _BuyFormState extends ConsumerState<BuyForm> { ], ), ); - }) + }, + ) : await Navigator.of(context).push( MaterialPageRoute<dynamic>( builder: (_) => CryptoSelectionView( @@ -386,7 +388,8 @@ class _BuyFormState extends ConsumerState<BuyForm> { ], ), ); - }) + }, + ) : await Navigator.of(context).push( MaterialPageRoute<dynamic>( builder: (_) => FiatSelectionView( @@ -410,7 +413,7 @@ class _BuyFormState extends ConsumerState<BuyForm> { if (ticker == null) return false; try { - coinFromTickerCaseInsensitive(ticker); + SupportedCoins.getCryptoCurrencyForTicker(ticker); return true; } on ArgumentError catch (_) { return false; @@ -501,7 +504,7 @@ class _BuyFormState extends ConsumerState<BuyForm> { ), ), ], - ) + ), ], ), ), @@ -517,9 +520,10 @@ class _BuyFormState extends ConsumerState<BuyForm> { child: Text( "Ok", style: STextStyles.button(context).copyWith( - color: Theme.of(context) - .extension<StackColors>()! - .accentColorDark), + color: Theme.of(context) + .extension<StackColors>()! + .accentColorDark, + ), ), onPressed: () { Navigator.of(context).pop(); @@ -589,7 +593,7 @@ class _BuyFormState extends ConsumerState<BuyForm> { ), ), ], - ) + ), ], ), ), @@ -606,9 +610,10 @@ class _BuyFormState extends ConsumerState<BuyForm> { child: Text( "Ok", style: STextStyles.button(context).copyWith( - color: Theme.of(context) - .extension<StackColors>()! - .accentColorDark), + color: Theme.of(context) + .extension<StackColors>()! + .accentColorDark, + ), ), onPressed: () { Navigator.of(context).pop(); @@ -701,7 +706,8 @@ class _BuyFormState extends ConsumerState<BuyForm> { ], ), ); - }) + }, + ) : await Navigator.of(context).push( MaterialPageRoute<dynamic>( builder: (_) => BuyQuotePreviewView( @@ -742,7 +748,7 @@ class _BuyFormState extends ConsumerState<BuyForm> { Fiat.fromJson({'ticker': 'USD', 'name': 'United States Dollar'}); selectedCrypto = Crypto.fromJson({ 'ticker': widget.coin?.ticker ?? 'BTC', - 'name': widget.coin?.prettyName ?? 'Bitcoin' + 'name': widget.coin?.prettyName ?? 'Bitcoin', }); // THIS IS BAD. No way to be certain the simplex ticker points to the same @@ -907,7 +913,9 @@ class _BuyFormState extends ConsumerState<BuyForm> { children: <Widget>[ Container( padding: const EdgeInsets.symmetric( - vertical: 3, horizontal: 6), + vertical: 3, + horizontal: 6, + ), decoration: BoxDecoration( color: Theme.of(context) .extension<StackColors>()! @@ -916,12 +924,14 @@ class _BuyFormState extends ConsumerState<BuyForm> { ), child: Text( format.simpleCurrencySymbol( - selectedFiat?.ticker ?? "ERR".toUpperCase()), + selectedFiat?.ticker ?? "ERR".toUpperCase(), + ), textAlign: TextAlign.center, style: STextStyles.smallMed12(context).copyWith( - color: Theme.of(context) - .extension<StackColors>()! - .accentColorDark), + color: Theme.of(context) + .extension<StackColors>()! + .accentColorDark, + ), ), ), const SizedBox( @@ -976,7 +986,7 @@ class _BuyFormState extends ConsumerState<BuyForm> { }); validateAmount(); }, - ) + ), ], ), SizedBox( @@ -1026,47 +1036,53 @@ class _BuyFormState extends ConsumerState<BuyForm> { fit: BoxFit.scaleDown, child: Padding( padding: const EdgeInsets.all(12), - child: Row(children: [ - const SizedBox(width: 2), - buyWithFiat - ? Container( - padding: const EdgeInsets.symmetric( - vertical: 3, horizontal: 6), - decoration: BoxDecoration( - color: Theme.of(context) - .extension<StackColors>()! - .currencyListItemBG, - borderRadius: BorderRadius.circular(4), - ), - child: Text( - format.simpleCurrencySymbol( - selectedFiat?.ticker.toUpperCase() ?? - "ERR"), - textAlign: TextAlign.center, - style: STextStyles.smallMed12(context).copyWith( + child: Row( + children: [ + const SizedBox(width: 2), + buyWithFiat + ? Container( + padding: const EdgeInsets.symmetric( + vertical: 3, + horizontal: 6, + ), + decoration: BoxDecoration( + color: Theme.of(context) + .extension<StackColors>()! + .currencyListItemBG, + borderRadius: BorderRadius.circular(4), + ), + child: Text( + format.simpleCurrencySymbol( + selectedFiat?.ticker.toUpperCase() ?? "ERR", + ), + textAlign: TextAlign.center, + style: + STextStyles.smallMed12(context).copyWith( color: Theme.of(context) .extension<StackColors>()! - .accentColorDark), + .accentColorDark, + ), + ), + ) + : CoinIconForTicker( + ticker: selectedCrypto?.ticker ?? "BTC", + size: 20, ), - ) - : CoinIconForTicker( - ticker: selectedCrypto?.ticker ?? "BTC", - size: 20, - ), - SizedBox( - width: buyWithFiat - ? 8 - : 10), // maybe make isDesktop-aware? - Text( - buyWithFiat - ? selectedFiat?.ticker ?? "ERR" - : selectedCrypto?.ticker ?? "ERR", - style: STextStyles.smallMed14(context).copyWith( + SizedBox( + width: buyWithFiat ? 8 : 10, + ), // maybe make isDesktop-aware? + Text( + buyWithFiat + ? selectedFiat?.ticker ?? "ERR" + : selectedCrypto?.ticker ?? "ERR", + style: STextStyles.smallMed14(context).copyWith( color: Theme.of(context) .extension<StackColors>()! - .accentColorDark), - ), - ]), + .accentColorDark, + ), + ), + ], + ), ), ), suffixIcon: Padding( @@ -1078,7 +1094,8 @@ class _BuyFormState extends ConsumerState<BuyForm> { _buyAmountController.text.isNotEmpty ? TextFieldIconButton( key: const Key( - "buyViewClearAmountFieldButtonKey"), + "buyViewClearAmountFieldButtonKey", + ), onTap: () { // if (_BuyFormState.buyWithFiat) { // _buyAmountController.text = _BuyFormState @@ -1099,7 +1116,8 @@ class _BuyFormState extends ConsumerState<BuyForm> { ) : TextFieldIconButton( key: const Key( - "buyViewPasteAddressFieldButtonKey"), + "buyViewPasteAddressFieldButtonKey", + ), onTap: () async { final ClipboardData? data = await clipboard .getData(Clipboard.kTextPlain); @@ -1150,7 +1168,7 @@ class _BuyFormState extends ConsumerState<BuyForm> { text: "Choose from Stack", onTap: () { try { - final coin = coinFromTickerCaseInsensitive( + final coin = SupportedCoins.getCryptoCurrencyForTicker( selectedCrypto!.ticker, ); Navigator.of(context) @@ -1236,7 +1254,8 @@ class _BuyFormState extends ConsumerState<BuyForm> { _addressToggleFlag ? TextFieldIconButton( key: const Key( - "buyViewClearAddressFieldButtonKey"), + "buyViewClearAddressFieldButtonKey", + ), onTap: () { _receiveAddressController.text = ""; _address = ""; @@ -1248,7 +1267,8 @@ class _BuyFormState extends ConsumerState<BuyForm> { ) : TextFieldIconButton( key: const Key( - "buyViewPasteAddressFieldButtonKey"), + "buyViewPasteAddressFieldButtonKey", + ), onTap: () async { final ClipboardData? data = await clipboard .getData(Clipboard.kTextPlain); @@ -1257,7 +1277,9 @@ class _BuyFormState extends ConsumerState<BuyForm> { String content = data.text!.trim(); if (content.contains("\n")) { content = content.substring( - 0, content.indexOf("\n")); + 0, + content.indexOf("\n"), + ); } _receiveAddressController.text = content; @@ -1300,7 +1322,8 @@ class _BuyFormState extends ConsumerState<BuyForm> { child: Text( "Address book", style: STextStyles.desktopH3( - context), + context, + ), ), ), const DesktopDialogCloseButton(), @@ -1308,9 +1331,15 @@ class _BuyFormState extends ConsumerState<BuyForm> { ), Expanded( child: AddressBookAddressChooser( - coin: coinFromTickerCaseInsensitive( - selectedCrypto!.ticker - .toString()), + coin: SupportedCoins + .cryptocurrencies + .firstWhere( + (e) => + e.ticker.toLowerCase() == + selectedCrypto!.ticker + .toString() + .toLowerCase(), + ), ), ), ], @@ -1352,21 +1381,25 @@ class _BuyFormState extends ConsumerState<BuyForm> { if (FocusScope.of(context).hasFocus) { FocusScope.of(context).unfocus(); await Future<void>.delayed( - const Duration(milliseconds: 75)); + const Duration(milliseconds: 75), + ); } final qrResult = await scanner.scan(); Logging.instance.log( - "qrResult content: ${qrResult.rawContent}", - level: LogLevel.Info); + "qrResult content: ${qrResult.rawContent}", + level: LogLevel.Info, + ); final results = AddressUtils.parseUri( - qrResult.rawContent); + qrResult.rawContent, + ); Logging.instance.log( - "qrResult parsed: $results", - level: LogLevel.Info); + "qrResult parsed: $results", + level: LogLevel.Info, + ); if (results.isNotEmpty) { // auto fill address diff --git a/lib/pages/buy_view/buy_in_wallet_view.dart b/lib/pages/buy_view/buy_in_wallet_view.dart index b0183eb79..18f4d643a 100644 --- a/lib/pages/buy_view/buy_in_wallet_view.dart +++ b/lib/pages/buy_view/buy_in_wallet_view.dart @@ -12,21 +12,21 @@ import 'package:flutter/material.dart'; import 'package:stackwallet/models/isar/models/ethereum/eth_contract.dart'; import 'package:stackwallet/pages/buy_view/buy_view.dart'; import 'package:stackwallet/themes/stack_colors.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/background.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; class BuyInWalletView extends StatefulWidget { const BuyInWalletView({ - Key? key, + super.key, required this.coin, this.contract, - }) : super(key: key); + }); static const String routeName = "/stackBuyInWalletView"; - final Coin? coin; + final CryptoCurrency? coin; final EthContract? contract; @override @@ -34,7 +34,7 @@ class BuyInWalletView extends StatefulWidget { } class _BuyInWalletViewState extends State<BuyInWalletView> { - late final Coin? coin; + late final CryptoCurrency? coin; @override Widget build(BuildContext context) { diff --git a/lib/pages/buy_view/buy_view.dart b/lib/pages/buy_view/buy_view.dart index e87fa3398..5bfed3475 100644 --- a/lib/pages/buy_view/buy_view.dart +++ b/lib/pages/buy_view/buy_view.dart @@ -15,18 +15,18 @@ import 'package:stackwallet/pages/buy_view/buy_form.dart'; import 'package:stackwallet/services/event_bus/events/global/tor_connection_status_changed_event.dart'; import 'package:stackwallet/services/tor_service.dart'; import 'package:stackwallet/themes/stack_colors.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; import 'package:stackwallet/widgets/tor_subscription.dart'; class BuyView extends ConsumerStatefulWidget { const BuyView({ - Key? key, + super.key, this.coin, this.tokenContract, - }) : super(key: key); + }); - final Coin? coin; + final CryptoCurrency? coin; final EthContract? tokenContract; static const String routeName = "/stackBuyView"; @@ -36,7 +36,7 @@ class BuyView extends ConsumerStatefulWidget { } class _BuyViewState extends ConsumerState<BuyView> { - Coin? coin; + CryptoCurrency? coin; EthContract? tokenContract; late bool torEnabled; diff --git a/lib/pages/buy_view/sub_widgets/crypto_selection_view.dart b/lib/pages/buy_view/sub_widgets/crypto_selection_view.dart index b7ae75de0..bf101ec72 100644 --- a/lib/pages/buy_view/sub_widgets/crypto_selection_view.dart +++ b/lib/pages/buy_view/sub_widgets/crypto_selection_view.dart @@ -14,11 +14,11 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/models/buy/response_objects/crypto.dart'; +import 'package:stackwallet/supported_coins.dart'; import 'package:stackwallet/themes/coin_icon_provider.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; @@ -53,9 +53,11 @@ class _CryptoSelectionViewState extends ConsumerState<CryptoSelectionView> { void filter(String text) { setState(() { _coins = [ - ...coins.where((e) => - e.name.toLowerCase().contains(text.toLowerCase()) || - e.ticker.toLowerCase().contains(text.toLowerCase())) + ...coins.where( + (e) => + e.name.toLowerCase().contains(text.toLowerCase()) || + e.ticker.toLowerCase().contains(text.toLowerCase()), + ), ]; }); } @@ -66,10 +68,12 @@ class _CryptoSelectionViewState extends ConsumerState<CryptoSelectionView> { coins = [...widget.coins]; coins.sort( - (a, b) => a.ticker.toLowerCase().compareTo(b.ticker.toLowerCase())); - for (Coin coin in Coin.values.reversed) { - int index = coins.indexWhere((element) => - element.ticker.toLowerCase() == coin.ticker.toLowerCase()); + (a, b) => a.ticker.toLowerCase().compareTo(b.ticker.toLowerCase()), + ); + for (final coin in SupportedCoins.cryptocurrencies.reversed) { + final index = coins.indexWhere( + (element) => element.ticker.toLowerCase() == coin.ticker.toLowerCase(), + ); if (index > 0) { final currency = coins.removeAt(index); coins.insert(0, currency); @@ -104,7 +108,8 @@ class _CryptoSelectionViewState extends ConsumerState<CryptoSelectionView> { if (FocusScope.of(context).hasFocus) { FocusScope.of(context).unfocus(); await Future<void>.delayed( - const Duration(milliseconds: 50)); + const Duration(milliseconds: 50), + ); } if (mounted) { Navigator.of(context).pop(); @@ -265,7 +270,7 @@ bool isStackCoin(String? ticker) { if (ticker == null) return false; try { - coinFromTickerCaseInsensitive(ticker); + SupportedCoins.getCryptoCurrencyForTicker(ticker); return true; } on ArgumentError catch (_) { return false; @@ -289,10 +294,10 @@ bool isStackCoin(String? ticker) { /// caller must ensure [Coin] for ticker exists class CoinIconForTicker extends ConsumerWidget { const CoinIconForTicker({ - Key? key, + super.key, required this.ticker, required this.size, - }) : super(key: key); + }); final String ticker; final double size; @@ -300,7 +305,7 @@ class CoinIconForTicker extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { try { - final coin = coinFromTickerCaseInsensitive(ticker); + final coin = SupportedCoins.getCryptoCurrencyForTicker(ticker); return SvgPicture.file( File( ref.watch(coinIconProvider(coin)), @@ -321,7 +326,7 @@ class CoinIconForTicker extends ConsumerWidget { // }) { // String? iconAsset = /*isStackCoin(ticker) // ?*/ -// Assets.svg.iconFor(coin: coinFromTickerCaseInsensitive(ticker)); +// Assets.svg.iconFor(coin: SupportedCoins.getCryptoCurrencyForTicker(ticker)); // // : Assets.svg.buyIconFor(ticker); // return (iconAsset != null) // ? SvgPicture.asset(iconAsset, height: size, width: size) diff --git a/lib/pages/cashfusion/cashfusion_view.dart b/lib/pages/cashfusion/cashfusion_view.dart index 5de0003d9..ff058859e 100644 --- a/lib/pages/cashfusion/cashfusion_view.dart +++ b/lib/pages/cashfusion/cashfusion_view.dart @@ -23,8 +23,8 @@ import 'package:stackwallet/providers/global/wallets_provider.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/cash_fusion_interface.dart'; import 'package:stackwallet/widgets/background.dart'; @@ -56,7 +56,7 @@ class _CashFusionViewState extends ConsumerState<CashFusionView> { late final FocusNode portFocusNode; late final TextEditingController fusionRoundController; late final FocusNode fusionRoundFocusNode; - late final Coin coin; + late final CryptoCurrency coin; bool _enableSSLCheckbox = false; bool _enableStartButton = false; diff --git a/lib/pages/cashfusion/fusion_progress_view.dart b/lib/pages/cashfusion/fusion_progress_view.dart index 78bc9ccc7..40844cde7 100644 --- a/lib/pages/cashfusion/fusion_progress_view.dart +++ b/lib/pages/cashfusion/fusion_progress_view.dart @@ -17,10 +17,10 @@ import 'package:stackwallet/providers/cash_fusion/fusion_progress_ui_state_provi import 'package:stackwallet/providers/global/prefs_provider.dart'; import 'package:stackwallet/providers/global/wallets_provider.dart'; import 'package:stackwallet/themes/stack_colors.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/show_loading.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/cash_fusion_interface.dart'; import 'package:stackwallet/widgets/background.dart'; @@ -44,7 +44,7 @@ class FusionProgressView extends ConsumerStatefulWidget { } class _FusionProgressViewState extends ConsumerState<FusionProgressView> { - late final Coin coin; + late final CryptoCurrency coin; Future<bool> _requestAndProcessCancel() async { final shouldCancel = await showDialog<bool?>( diff --git a/lib/pages/coin_control/coin_control_view.dart b/lib/pages/coin_control/coin_control_view.dart index b57281dd7..b82b13914 100644 --- a/lib/pages/coin_control/coin_control_view.dart +++ b/lib/pages/coin_control/coin_control_view.dart @@ -24,7 +24,6 @@ import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount_formatter.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/coin_control_interface.dart'; @@ -49,12 +48,12 @@ enum CoinControlViewType { class CoinControlView extends ConsumerStatefulWidget { const CoinControlView({ - Key? key, + super.key, required this.walletId, required this.type, this.requestedTotal, this.selectedUTXOs, - }) : super(key: key); + }); static const routeName = "/coinControl"; @@ -128,7 +127,7 @@ class _CoinControlViewState extends ConsumerState<CoinControlView> { filter: CCFilter.all, sort: _sort, searchTerm: "", - coin: coin, + cryptoCurrency: coin, ); } else { _map = null; @@ -141,7 +140,7 @@ class _CoinControlViewState extends ConsumerState<CoinControlView> { : CCFilter.available, sort: _sort, searchTerm: _isSearching ? searchController.text : "", - coin: coin, + cryptoCurrency: coin, ); } @@ -682,7 +681,7 @@ class _CoinControlViewState extends ConsumerState<CoinControlView> { ); final selectedSum = selectedSumInt.toAmountAsRaw( - fractionDigits: coin.decimals, + fractionDigits: coin.fractionDigits, ); return Text( ref diff --git a/lib/pages/coin_control/utxo_card.dart b/lib/pages/coin_control/utxo_card.dart index 74c5d3b82..5688d2b2a 100644 --- a/lib/pages/coin_control/utxo_card.dart +++ b/lib/pages/coin_control/utxo_card.dart @@ -17,7 +17,6 @@ import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount_formatter.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; import 'package:stackwallet/widgets/conditional_parent.dart'; @@ -26,14 +25,14 @@ import 'package:stackwallet/widgets/rounded_container.dart'; class UtxoCard extends ConsumerStatefulWidget { const UtxoCard({ - Key? key, + super.key, required this.utxo, required this.walletId, required this.onSelectedChanged, required this.initialSelectedState, required this.canSelect, this.onPressed, - }) : super(key: key); + }); final String walletId; final UTXO utxo; @@ -138,7 +137,7 @@ class _UtxoCardState extends ConsumerState<UtxoCard> { Text( ref.watch(pAmountFormatter(coin)).format( utxo.value.toAmountAsRaw( - fractionDigits: coin.decimals, + fractionDigits: coin.fractionDigits, ), ), style: STextStyles.w600_14(context), diff --git a/lib/pages/coin_control/utxo_details_view.dart b/lib/pages/coin_control/utxo_details_view.dart index 7c32fee2f..ce6dce597 100644 --- a/lib/pages/coin_control/utxo_details_view.dart +++ b/lib/pages/coin_control/utxo_details_view.dart @@ -20,7 +20,6 @@ import 'package:stackwallet/providers/global/wallets_provider.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount_formatter.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; @@ -37,10 +36,10 @@ import 'package:stackwallet/widgets/rounded_container.dart'; class UtxoDetailsView extends ConsumerStatefulWidget { const UtxoDetailsView({ - Key? key, + super.key, required this.utxoId, required this.walletId, - }) : super(key: key); + }); static const routeName = "/utxoDetails"; @@ -244,7 +243,7 @@ class _UtxoDetailsViewState extends ConsumerState<UtxoDetailsView> { Text( ref.watch(pAmountFormatter(coin)).format( utxo!.value.toAmountAsRaw( - fractionDigits: coin.decimals, + fractionDigits: coin.fractionDigits, ), ), style: STextStyles.pageTitleH2(context), diff --git a/lib/pages/exchange_view/choose_from_stack_view.dart b/lib/pages/exchange_view/choose_from_stack_view.dart index 553c11628..d6aa4f837 100644 --- a/lib/pages/exchange_view/choose_from_stack_view.dart +++ b/lib/pages/exchange_view/choose_from_stack_view.dart @@ -13,8 +13,8 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; import 'package:stackwallet/widgets/background.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; @@ -24,11 +24,11 @@ import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_ class ChooseFromStackView extends ConsumerStatefulWidget { const ChooseFromStackView({ - Key? key, + super.key, required this.coin, - }) : super(key: key); + }); - final Coin coin; + final CryptoCurrency coin; static const String routeName = "/chooseFromStack"; @@ -38,7 +38,7 @@ class ChooseFromStackView extends ConsumerStatefulWidget { } class _ChooseFromStackViewState extends ConsumerState<ChooseFromStackView> { - late final Coin coin; + late final CryptoCurrency coin; @override void initState() { diff --git a/lib/pages/exchange_view/confirm_change_now_send.dart b/lib/pages/exchange_view/confirm_change_now_send.dart index 85072c98c..5135d96ee 100644 --- a/lib/pages/exchange_view/confirm_change_now_send.dart +++ b/lib/pages/exchange_view/confirm_change_now_send.dart @@ -26,7 +26,6 @@ import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount_formatter.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; @@ -47,14 +46,14 @@ import 'package:uuid/uuid.dart'; class ConfirmChangeNowSendView extends ConsumerStatefulWidget { const ConfirmChangeNowSendView({ - Key? key, + super.key, required this.txData, required this.walletId, this.routeOnSuccessName = WalletView.routeName, required this.trade, this.shouldSendPublicFiroFunds, this.fromDesktopStep4 = false, - }) : super(key: key); + }); static const String routeName = "/confirmChangeNowSend"; diff --git a/lib/pages/exchange_view/exchange_coin_selection/exchange_currency_selection_view.dart b/lib/pages/exchange_view/exchange_coin_selection/exchange_currency_selection_view.dart index 3a23ea331..7698d875b 100644 --- a/lib/pages/exchange_view/exchange_coin_selection/exchange_currency_selection_view.dart +++ b/lib/pages/exchange_view/exchange_coin_selection/exchange_currency_selection_view.dart @@ -22,10 +22,10 @@ import 'package:stackwallet/services/exchange/exchange.dart'; import 'package:stackwallet/services/exchange/exchange_data_loading_service.dart'; import 'package:stackwallet/services/exchange/majestic_bank/majestic_bank_exchange.dart'; import 'package:stackwallet/services/exchange/trocador/trocador_exchange.dart'; +import 'package:stackwallet/supported_coins.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/prefs.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; @@ -143,7 +143,8 @@ class _ExchangeCurrencySelectionViewState onPressed: () async { Navigator.of(context, rootNavigator: isDesktop).pop(); _currencies = await _showUpdatingCurrencies( - whileFuture: _loadCurrencies()); + whileFuture: _loadCurrencies(), + ); setState(() {}); }, ), @@ -164,15 +165,17 @@ class _ExchangeCurrencySelectionViewState .filter() .isFiatEqualTo(false) .and() - .group((q) => widget.isFixedRate - ? q - .rateTypeEqualTo(SupportedRateType.both) - .or() - .rateTypeEqualTo(SupportedRateType.fixed) - : q - .rateTypeEqualTo(SupportedRateType.both) - .or() - .rateTypeEqualTo(SupportedRateType.estimated)) + .group( + (q) => widget.isFixedRate + ? q + .rateTypeEqualTo(SupportedRateType.both) + .or() + .rateTypeEqualTo(SupportedRateType.fixed) + : q + .rateTypeEqualTo(SupportedRateType.both) + .or() + .rateTypeEqualTo(SupportedRateType.estimated), + ) .sortByIsStackCoin() .thenByName() .findAll(); @@ -180,9 +183,10 @@ class _ExchangeCurrencySelectionViewState // If using Tor, filter exchanges which do not support Tor. if (Prefs.instance.useTor) { if (Exchange.exchangeNamesWithTorSupport.isNotEmpty) { - currencies.removeWhere((element) => !Exchange - .exchangeNamesWithTorSupport - .contains(element.exchangeName)); + currencies.removeWhere( + (element) => !Exchange.exchangeNamesWithTorSupport + .contains(element.exchangeName), + ); } } @@ -193,7 +197,8 @@ class _ExchangeCurrencySelectionViewState final List<Currency> distinctCurrencies = []; for (final currency in currencies) { if (!distinctCurrencies.any( - (e) => e.ticker.toLowerCase() == currency.ticker.toLowerCase())) { + (e) => e.ticker.toLowerCase() == currency.ticker.toLowerCase(), + )) { distinctCurrencies.add(currency); } } @@ -207,23 +212,29 @@ class _ExchangeCurrencySelectionViewState } return _currencies - .where((e) => - e.name.toLowerCase().contains(text.toLowerCase()) || - e.ticker.toLowerCase().contains(text.toLowerCase())) + .where( + (e) => + e.name.toLowerCase().contains(text.toLowerCase()) || + e.ticker.toLowerCase().contains(text.toLowerCase()), + ) .toList(); } else { if (text.isEmpty) { return _currencies - .where((e) => - e.ticker.toLowerCase() != widget.pairedTicker!.toLowerCase()) + .where( + (e) => + e.ticker.toLowerCase() != widget.pairedTicker!.toLowerCase(), + ) .toList(); } return _currencies - .where((e) => - e.ticker.toLowerCase() != widget.pairedTicker!.toLowerCase() && - (e.name.toLowerCase().contains(text.toLowerCase()) || - e.ticker.toLowerCase().contains(text.toLowerCase()))) + .where( + (e) => + e.ticker.toLowerCase() != widget.pairedTicker!.toLowerCase() && + (e.name.toLowerCase().contains(text.toLowerCase()) || + e.ticker.toLowerCase().contains(text.toLowerCase())), + ) .toList(); } } @@ -266,7 +277,8 @@ class _ExchangeCurrencySelectionViewState if (FocusScope.of(context).hasFocus) { FocusScope.of(context).unfocus(); await Future<void>.delayed( - const Duration(milliseconds: 50)); + const Duration(milliseconds: 50), + ); } if (mounted) { Navigator.of(context).pop(); @@ -353,18 +365,24 @@ class _ExchangeCurrencySelectionViewState Flexible( child: Builder( builder: (context) { - final coins = Coin.values.where((e) => - e.ticker.toLowerCase() != - widget.pairedTicker?.toLowerCase()); + final coins = SupportedCoins.cryptocurrencies.where( + (e) => + e.ticker.toLowerCase() != + widget.pairedTicker?.toLowerCase(), + ); final items = filter(_searchString); final walletCoins = items - .where((currency) => coins - .where((coin) => - coin.ticker.toLowerCase() == - currency.ticker.toLowerCase()) - .isNotEmpty) + .where( + (currency) => coins + .where( + (coin) => + coin.ticker.toLowerCase() == + currency.ticker.toLowerCase(), + ) + .isNotEmpty, + ) .toList(); // sort alphabetically by name @@ -402,7 +420,9 @@ class _ExchangeCurrencySelectionViewState height: 24, child: isStackCoin(items[index].ticker) ? CoinIconForTicker( - ticker: items[index].ticker, size: 24) + ticker: items[index].ticker, + size: 24, + ) // ? getIconForTicker( // items[index].ticker, // size: 24, diff --git a/lib/pages/exchange_view/exchange_form.dart b/lib/pages/exchange_view/exchange_form.dart index a233a35c7..2dbd40094 100644 --- a/lib/pages/exchange_view/exchange_form.dart +++ b/lib/pages/exchange_view/exchange_form.dart @@ -40,10 +40,11 @@ import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/amount/amount_unit.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/exchange_rate_type_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/bitcoin.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/conditional_parent.dart'; import 'package:stackwallet/widgets/custom_loading_overlay.dart'; import 'package:stackwallet/widgets/desktop/desktop_dialog.dart'; @@ -59,14 +60,14 @@ import 'package:uuid/uuid.dart'; class ExchangeForm extends ConsumerStatefulWidget { const ExchangeForm({ - Key? key, + super.key, this.walletId, this.coin, this.contract, - }) : super(key: key); + }); final String? walletId; - final Coin? coin; + final CryptoCurrency? coin; final EthContract? contract; @override @@ -75,7 +76,7 @@ class ExchangeForm extends ConsumerStatefulWidget { class _ExchangeFormState extends ConsumerState<ExchangeForm> { late final String? walletId; - late final Coin? coin; + late final CryptoCurrency? coin; late final bool walletInitiated; List<Exchange> get usableExchanges { @@ -172,7 +173,8 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> { .tryParse( value, locale: ref.read(localeServiceChangeNotifierProvider).locale, - coin: Coin.bitcoin, // dummy value (not used due to override) + coin: Bitcoin(CryptoCurrencyNetwork + .main), // dummy value (not used due to override) overrideWithDecimalPlacesFromString: true, ) ?.decimal; @@ -607,12 +609,12 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> { } } - bool isWalletCoin(Coin? coin, bool isSend) { + bool isWalletCoin(CryptoCurrency? coin, bool isSend) { if (coin == null) { return false; } - String? ticker = isSend + final String? ticker = isSend ? ref.read(efCurrencyPairProvider).send?.ticker : ref.read(efCurrencyPairProvider).receive?.ticker; diff --git a/lib/pages/exchange_view/exchange_step_views/step_2_view.dart b/lib/pages/exchange_view/exchange_step_views/step_2_view.dart index 95734e94c..5f4ed4a6b 100644 --- a/lib/pages/exchange_view/exchange_step_views/step_2_view.dart +++ b/lib/pages/exchange_view/exchange_step_views/step_2_view.dart @@ -19,12 +19,12 @@ import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_3_view. import 'package:stackwallet/pages/exchange_view/sub_widgets/step_row.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/services/exchange/majestic_bank/majestic_bank_exchange.dart'; +import 'package:stackwallet/supported_coins.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/address_utils.dart'; import 'package:stackwallet/utilities/barcode_scanner_interface.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/widgets/background.dart'; @@ -72,7 +72,7 @@ class _Step2ViewState extends ConsumerState<Step2View> { bool isStackCoin(String ticker) { try { - coinFromTickerCaseInsensitive(ticker); + SupportedCoins.getCryptoCurrencyForTicker(ticker); return true; } on ArgumentError catch (_) { return false; @@ -207,10 +207,13 @@ class _Step2ViewState extends ConsumerState<Step2View> { text: "Choose from Stack", onTap: () { try { - final coin = - coinFromTickerCaseInsensitive( - model.receiveTicker, - ); + final coin = SupportedCoins + .cryptocurrencies + .firstWhere((e) => + e.ticker.toLowerCase() == + model.receiveTicker + .toLowerCase()); + Navigator.of(context) .pushNamed( ChooseFromStackView.routeName, @@ -480,10 +483,12 @@ class _Step2ViewState extends ConsumerState<Step2View> { text: "Choose from Stack", onTap: () { try { - final coin = - coinFromTickerCaseInsensitive( - model.sendTicker, - ); + final coin = SupportedCoins + .cryptocurrencies + .firstWhere((e) => + e.ticker.toLowerCase() == + model.sendTicker.toLowerCase()); + Navigator.of(context) .pushNamed( ChooseFromStackView.routeName, diff --git a/lib/pages/exchange_view/exchange_step_views/step_4_view.dart b/lib/pages/exchange_view/exchange_step_views/step_4_view.dart index 496975116..ba9e37ad6 100644 --- a/lib/pages/exchange_view/exchange_step_views/step_4_view.dart +++ b/lib/pages/exchange_view/exchange_step_views/step_4_view.dart @@ -26,15 +26,18 @@ import 'package:stackwallet/pages/send_view/sub_widgets/building_transaction_dia import 'package:stackwallet/pages/wallet_view/wallet_view.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/route_generator.dart'; +import 'package:stackwallet/supported_coins.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount_formatter.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/stellar.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; import 'package:stackwallet/wallets/models/tx_data.dart'; import 'package:stackwallet/wallets/wallet/impl/firo_wallet.dart'; @@ -72,7 +75,7 @@ class _Step4ViewState extends ConsumerState<Step4View> { bool _isWalletCoinAndHasWallet(String ticker, WidgetRef ref) { try { - final coin = coinFromTickerCaseInsensitive(ticker); + final coin = SupportedCoins.getCryptoCurrencyForTicker(ticker); return ref .read(pWallets) .wallets @@ -194,9 +197,9 @@ class _Step4ViewState extends ConsumerState<Step4View> { ); } - Future<void> _confirmSend(Tuple2<String, Coin> tuple) async { + Future<void> _confirmSend(Tuple2<String, CryptoCurrency> tuple) async { final bool firoPublicSend; - if (tuple.item2 == Coin.firo) { + if (tuple.item2 is Firo) { final result = await _showSendFromFiroBalanceSelectSheet(tuple.item1); if (result == null) { return; @@ -210,7 +213,7 @@ class _Step4ViewState extends ConsumerState<Step4View> { final wallet = ref.read(pWallets).getWallet(tuple.item1); final Amount amount = model.sendAmount.toAmount( - fractionDigits: wallet.info.coin.decimals, + fractionDigits: wallet.info.coin.fractionDigits, ); final address = model.trade!.payInAddress; @@ -258,8 +261,7 @@ class _Step4ViewState extends ConsumerState<Step4View> { ), ); } else { - final memo = wallet.info.coin == Coin.stellar || - wallet.info.coin == Coin.stellarTestnet + final memo = wallet.info.coin is Stellar ? model.trade!.payInExtraId.isNotEmpty ? model.trade!.payInExtraId : null @@ -851,16 +853,23 @@ class _Step4ViewState extends ConsumerState<Step4View> { .useMaterialPageRoute, builder: (BuildContext context) { - final coin = - coinFromTickerCaseInsensitive( - model.trade!.payInCurrency, + final coin = SupportedCoins + .cryptocurrencies + .firstWhere( + (e) => + e.ticker + .toLowerCase() == + model.trade! + .payInCurrency + .toLowerCase(), ); + return SendFromView( coin: coin, amount: model.sendAmount .toAmount( fractionDigits: - coin.decimals, + coin.fractionDigits, ), address: model .trade!.payInAddress, diff --git a/lib/pages/exchange_view/send_from_view.dart b/lib/pages/exchange_view/send_from_view.dart index a97b94a28..b0dbd0252 100644 --- a/lib/pages/exchange_view/send_from_view.dart +++ b/lib/pages/exchange_view/send_from_view.dart @@ -23,14 +23,17 @@ import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/route_generator.dart'; import 'package:stackwallet/themes/coin_icon_provider.dart'; import 'package:stackwallet/themes/stack_colors.dart'; +import 'package:stackwallet/themes/theme_providers.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount_formatter.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/stellar.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; import 'package:stackwallet/wallets/models/tx_data.dart'; import 'package:stackwallet/wallets/wallet/impl/firo_wallet.dart'; @@ -56,7 +59,7 @@ class SendFromView extends ConsumerStatefulWidget { static const String routeName = "/sendFrom"; - final Coin coin; + final CryptoCurrency coin; final Amount amount; final String address; final Trade trade; @@ -68,7 +71,7 @@ class SendFromView extends ConsumerStatefulWidget { } class _SendFromViewState extends ConsumerState<SendFromView> { - late final Coin coin; + late final CryptoCurrency coin; late final Amount amount; late final String address; late final Trade trade; @@ -279,7 +282,7 @@ class _SendFromCardState extends ConsumerState<SendFromCard> { // if not firo then do normal send if (shouldSendPublicFiroFunds == null) { - final memo = coin == Coin.stellar || coin == Coin.stellarTestnet + final memo = coin is Stellar ? trade.payInExtraId.isNotEmpty ? trade.payInExtraId : null @@ -427,7 +430,7 @@ class _SendFromCardState extends ConsumerState<SendFromCard> { final coin = ref.watch(pWalletCoin(walletId)); - final isFiro = coin == Coin.firoTestNet || coin == Coin.firo; + final isFiro = coin is Firo; return RoundedWhiteContainer( padding: const EdgeInsets.all(0), @@ -602,10 +605,7 @@ class _SendFromCardState extends ConsumerState<SendFromCard> { children: [ Container( decoration: BoxDecoration( - color: Theme.of(context) - .extension<StackColors>()! - .colorForCoin(coin) - .withOpacity(0.5), + color: ref.watch(pCoinColor(coin)).withOpacity(0.5), borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, ), diff --git a/lib/pages/exchange_view/sub_widgets/exchange_provider_option.dart b/lib/pages/exchange_view/sub_widgets/exchange_provider_option.dart index e891f148e..926fa5ddb 100644 --- a/lib/pages/exchange_view/sub_widgets/exchange_provider_option.dart +++ b/lib/pages/exchange_view/sub_widgets/exchange_provider_option.dart @@ -16,16 +16,18 @@ import 'package:stackwallet/models/exchange/response_objects/estimate.dart'; import 'package:stackwallet/providers/exchange/exchange_form_state_provider.dart'; import 'package:stackwallet/providers/global/locale_provider.dart'; import 'package:stackwallet/services/exchange/exchange.dart'; +import 'package:stackwallet/supported_coins.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount_formatter.dart'; import 'package:stackwallet/utilities/amount/amount_unit.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/exchange_rate_type_enum.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/bitcoin.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/animated_text.dart'; import 'package:stackwallet/widgets/conditional_parent.dart'; import 'package:stackwallet/widgets/exchange/trocador/trocador_kyc_info_button.dart'; @@ -33,11 +35,11 @@ import 'package:stackwallet/widgets/exchange/trocador/trocador_rating_type_enum. class ExchangeOption extends ConsumerStatefulWidget { const ExchangeOption({ - Key? key, + super.key, required this.exchange, required this.fixedRate, required this.reversed, - }) : super(key: key); + }); final Exchange exchange; final bool fixedRate; @@ -92,9 +94,9 @@ class _ExchangeOptionState extends ConsumerState<ExchangeOption> { int decimals; try { - decimals = coinFromTickerCaseInsensitive( - receivingCurrency.ticker) - .decimals; + decimals = SupportedCoins.getCryptoCurrencyForTicker( + receivingCurrency.ticker, + ).fractionDigits; } catch (_) { decimals = 8; // some reasonable alternative } @@ -109,10 +111,11 @@ class _ExchangeOptionState extends ConsumerState<ExchangeOption> { .toAmount(fractionDigits: decimals); } - Coin? coin; + CryptoCurrency? coin; try { - coin = coinFromTickerCaseInsensitive( - receivingCurrency.ticker); + coin = SupportedCoins.getCryptoCurrencyForTicker( + receivingCurrency.ticker, + ); } catch (_) { coin = null; } @@ -128,7 +131,8 @@ class _ExchangeOptionState extends ConsumerState<ExchangeOption> { localeServiceChangeNotifierProvider .select((value) => value.locale), ), - coin: Coin.bitcoin, // some sane default + coin: Bitcoin(CryptoCurrencyNetwork + .main), // some sane default maxDecimals: 8, // some sane default ); rateString = "1 ${sendCurrency.ticker.toUpperCase()} " diff --git a/lib/pages/exchange_view/trade_details_view.dart b/lib/pages/exchange_view/trade_details_view.dart index ab3aa0b1f..33d516d8e 100644 --- a/lib/pages/exchange_view/trade_details_view.dart +++ b/lib/pages/exchange_view/trade_details_view.dart @@ -33,6 +33,7 @@ import 'package:stackwallet/services/exchange/exchange.dart'; import 'package:stackwallet/services/exchange/majestic_bank/majestic_bank_exchange.dart'; import 'package:stackwallet/services/exchange/simpleswap/simpleswap_exchange.dart'; import 'package:stackwallet/services/exchange/trocador/trocador_exchange.dart'; +import 'package:stackwallet/supported_coins.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/themes/theme_providers.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; @@ -40,10 +41,10 @@ import 'package:stackwallet/utilities/amount/amount_formatter.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/format.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/background.dart'; import 'package:stackwallet/widgets/conditional_parent.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; @@ -58,13 +59,13 @@ import 'package:url_launcher/url_launcher.dart'; class TradeDetailsView extends ConsumerStatefulWidget { const TradeDetailsView({ - Key? key, + super.key, required this.tradeId, required this.transactionIfSentFromStack, required this.walletId, required this.walletName, this.clipboard = const ClipboardWrapper(), - }) : super(key: key); + }); static const String routeName = "/tradeDetails"; @@ -87,9 +88,9 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> { bool isStackCoin(String ticker) { try { try { - coinFromTickerCaseInsensitive(ticker); + SupportedCoins.getCryptoCurrencyForTicker(ticker); } catch (_) {} - coinFromPrettyName(ticker); + SupportedCoins.getCryptoCurrencyByPrettyName(ticker); return true; } on ArgumentError catch (_) { return false; @@ -167,8 +168,11 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> { final bool sentFromStack = transactionIfSentFromStack != null && walletId != null; - final trade = ref.watch(tradesServiceProvider.select( - (value) => value.trades.firstWhere((e) => e.tradeId == tradeId))); + final trade = ref.watch( + tradesServiceProvider.select( + (value) => value.trades.firstWhere((e) => e.tradeId == tradeId), + ), + ); final bool hasTx = sentFromStack || !(trade.status == "New" || @@ -273,16 +277,19 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> { label: "Send from Stack", buttonHeight: ButtonHeight.l, onPressed: () { - Coin coin; + CryptoCurrency coin; try { - coin = coinFromTickerCaseInsensitive( - trade.payInCurrency); + coin = SupportedCoins.getCryptoCurrencyForTicker( + trade.payInCurrency, + ); } catch (_) { - coin = coinFromPrettyName(trade.payInCurrency); + coin = SupportedCoins.getCryptoCurrencyByPrettyName( + trade.payInCurrency, + ); } final amount = Amount.fromDecimal( sendAmount, - fractionDigits: coin.decimals, + fractionDigits: coin.fractionDigits, ); final address = trade.payInAddress; @@ -368,28 +375,34 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> { const SizedBox( height: 4, ), - Builder(builder: (context) { - String text; - try { - final coin = coinFromTickerCaseInsensitive( - trade.payInCurrency); - final amount = sendAmount.toAmount( - fractionDigits: coin.decimals); - text = ref - .watch(pAmountFormatter(coin)) - .format(amount); - } catch (_) { - text = sendAmount.toStringAsFixed( + Builder( + builder: (context) { + String text; + try { + final coin = + SupportedCoins.getCryptoCurrencyForTicker( + trade.payInCurrency, + ); + final amount = sendAmount.toAmount( + fractionDigits: coin.fractionDigits, + ); + text = ref + .watch(pAmountFormatter(coin)) + .format(amount); + } catch (_) { + text = sendAmount.toStringAsFixed( trade.payInCurrency.toLowerCase() == "xmr" ? 12 - : 8); - } + : 8, + ); + } - return SelectableText( - "-$text ${trade.payInCurrency.toUpperCase()}", - style: STextStyles.itemSubtitle(context), - ); - }), + return SelectableText( + "-$text ${trade.payInCurrency.toUpperCase()}", + style: STextStyles.itemSubtitle(context), + ); + }, + ), ], ), if (!isDesktop) @@ -464,7 +477,7 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> { ), ), ], - ) + ), ], ), const SizedBox( @@ -512,7 +525,8 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> { Text( "Amount", style: STextStyles.desktopTextExtraExtraSmall( - context), + context, + ), ), const SizedBox( height: 2, @@ -520,8 +534,8 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> { Text( "${trade.payInAmount} ${trade.payInCurrency.toUpperCase()}", style: STextStyles.desktopTextExtraExtraSmall( - context) - .copyWith( + context, + ).copyWith( color: Theme.of(context) .extension<StackColors>()! .textDark, @@ -542,43 +556,44 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> { ), child: RichText( text: TextSpan( - text: - "You must send at least ${sendAmount.toStringAsFixed( - trade.payInCurrency.toLowerCase() == "xmr" ? 12 : 8, - )} ${trade.payInCurrency.toUpperCase()}. ", - style: isDesktop - ? STextStyles.desktopTextExtraExtraSmall(context) - .copyWith( - color: Theme.of(context) - .extension<StackColors>()! - .accentColorRed) - : STextStyles.label(context).copyWith( - color: Theme.of(context) - .extension<StackColors>()! - .warningForeground, - ), - children: [ - TextSpan( - text: - "If you send less than ${sendAmount.toStringAsFixed( - trade.payInCurrency.toLowerCase() == "xmr" - ? 12 - : 8, - )} ${trade.payInCurrency.toUpperCase()}, your transaction may not be converted and it may not be refunded.", - style: isDesktop - ? STextStyles.desktopTextExtraExtraSmall( - context) - .copyWith( - color: Theme.of(context) - .extension<StackColors>()! - .accentColorRed) - : STextStyles.label(context).copyWith( - color: Theme.of(context) - .extension<StackColors>()! - .warningForeground, - ), - ), - ]), + text: + "You must send at least ${sendAmount.toStringAsFixed( + trade.payInCurrency.toLowerCase() == "xmr" ? 12 : 8, + )} ${trade.payInCurrency.toUpperCase()}. ", + style: isDesktop + ? STextStyles.desktopTextExtraExtraSmall(context) + .copyWith( + color: Theme.of(context) + .extension<StackColors>()! + .accentColorRed, + ) + : STextStyles.label(context).copyWith( + color: Theme.of(context) + .extension<StackColors>()! + .warningForeground, + ), + children: [ + TextSpan( + text: + "If you send less than ${sendAmount.toStringAsFixed( + trade.payInCurrency.toLowerCase() == "xmr" ? 12 : 8, + )} ${trade.payInCurrency.toUpperCase()}, your transaction may not be converted and it may not be refunded.", + style: isDesktop + ? STextStyles.desktopTextExtraExtraSmall( + context, + ).copyWith( + color: Theme.of(context) + .extension<StackColors>()! + .accentColorRed, + ) + : STextStyles.label(context).copyWith( + color: Theme.of(context) + .extension<StackColors>()! + .warningForeground, + ), + ), + ], + ), ), ), ), @@ -613,8 +628,10 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> { CustomTextButton( text: "View transaction", onTap: () { - final Coin coin = - coinFromTickerCaseInsensitive(trade.payInCurrency); + final CryptoCurrency coin = + SupportedCoins.getCryptoCurrencyForTicker( + trade.payInCurrency, + ); if (isDesktop) { Navigator.of(context).push( @@ -638,7 +655,10 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> { Navigator.of(context).pushNamed( TransactionDetailsView.routeName, arguments: Tuple3( - transactionIfSentFromStack!, coin, walletId!), + transactionIfSentFromStack!, + coin, + walletId!, + ), ); } }, @@ -787,14 +807,15 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> { width: width + 20, height: width + 20, child: QrImageView( - data: trade.payInAddress, - size: width, - backgroundColor: Theme.of(context) - .extension<StackColors>()! - .popupBG, - foregroundColor: Theme.of(context) - .extension<StackColors>()! - .accentColorDark), + data: trade.payInAddress, + size: width, + backgroundColor: Theme.of(context) + .extension<StackColors>()! + .popupBG, + foregroundColor: Theme.of(context) + .extension<StackColors>()! + .accentColorDark, + ), ), ), ), @@ -812,14 +833,16 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> { style: Theme.of(context) .extension<StackColors>()! .getSecondaryEnabledButtonStyle( - context), + context, + ), child: Text( "Cancel", style: STextStyles.button(context) .copyWith( - color: Theme.of(context) - .extension<StackColors>()! - .accentColorDark), + color: Theme.of(context) + .extension<StackColors>()! + .accentColorDark, + ), ), ), ), @@ -1005,8 +1028,10 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> { height: 4, ), SelectableText( - ref.watch(tradeNoteServiceProvider - .select((value) => value.getNote(tradeId: tradeId))), + ref.watch( + tradeNoteServiceProvider + .select((value) => value.getNote(tradeId: tradeId)), + ), style: STextStyles.itemSubtitle12(context), ), ], @@ -1132,7 +1157,8 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> { if (isDesktop) SelectableText( Format.extractDateFrom( - trade.timestamp.millisecondsSinceEpoch ~/ 1000), + trade.timestamp.millisecondsSinceEpoch ~/ 1000, + ), style: STextStyles.desktopTextExtraExtraSmall(context) .copyWith( color: Theme.of(context) @@ -1145,13 +1171,15 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> { if (!isDesktop) SelectableText( Format.extractDateFrom( - trade.timestamp.millisecondsSinceEpoch ~/ 1000), + trade.timestamp.millisecondsSinceEpoch ~/ 1000, + ), style: STextStyles.itemSubtitle12(context), ), if (isDesktop) IconCopyButton( data: Format.extractDateFrom( - trade.timestamp.millisecondsSinceEpoch ~/ 1000), + trade.timestamp.millisecondsSinceEpoch ~/ 1000, + ), ), ], ), @@ -1265,7 +1293,7 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> { .infoItemIcons, width: 12, ), - ) + ), ], ), ], @@ -1352,15 +1380,19 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> { SecondaryButton( label: "Send from Stack", onPressed: () { - Coin coin; + CryptoCurrency coin; try { - coin = coinFromTickerCaseInsensitive(trade.payInCurrency); + coin = SupportedCoins.getCryptoCurrencyForTicker( + trade.payInCurrency, + ); } catch (_) { - coin = coinFromPrettyName(trade.payInCurrency); + coin = SupportedCoins.getCryptoCurrencyByPrettyName( + trade.payInCurrency, + ); } final amount = Amount.fromDecimal( sendAmount, - fractionDigits: coin.decimals, + fractionDigits: coin.fractionDigits, ); final address = trade.payInAddress; diff --git a/lib/pages/exchange_view/wallet_initiated_exchange_view.dart b/lib/pages/exchange_view/wallet_initiated_exchange_view.dart index 3b6c41093..9804a46c2 100644 --- a/lib/pages/exchange_view/wallet_initiated_exchange_view.dart +++ b/lib/pages/exchange_view/wallet_initiated_exchange_view.dart @@ -19,8 +19,8 @@ import 'package:stackwallet/providers/exchange/exchange_form_state_provider.dart import 'package:stackwallet/providers/global/prefs_provider.dart'; import 'package:stackwallet/services/exchange/exchange_data_loading_service.dart'; import 'package:stackwallet/themes/stack_colors.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/background.dart'; import 'package:stackwallet/widgets/conditional_parent.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; @@ -28,16 +28,16 @@ import 'package:stackwallet/widgets/custom_loading_overlay.dart'; class WalletInitiatedExchangeView extends ConsumerStatefulWidget { const WalletInitiatedExchangeView({ - Key? key, + super.key, required this.walletId, required this.coin, this.contract, - }) : super(key: key); + }); static const String routeName = "/walletInitiatedExchange"; final String walletId; - final Coin coin; + final CryptoCurrency coin; final EthContract? contract; @override @@ -48,7 +48,7 @@ class WalletInitiatedExchangeView extends ConsumerStatefulWidget { class _WalletInitiatedExchangeViewState extends ConsumerState<WalletInitiatedExchangeView> { late final String walletId; - late final Coin coin; + late final CryptoCurrency coin; bool _initialCachePopulationUnderway = false; diff --git a/lib/pages/monkey/monkey_loaded_view.dart b/lib/pages/monkey/monkey_loaded_view.dart index 60f66a0ed..11c277b53 100644 --- a/lib/pages/monkey/monkey_loaded_view.dart +++ b/lib/pages/monkey/monkey_loaded_view.dart @@ -13,7 +13,7 @@ // // import 'package:stackwallet/themes/stack_colors.dart'; // import 'package:stackwallet/utilities/assets.dart'; -// import 'package:stackwallet/utilities/enums/coin_enum.dart'; +// // import 'package:stackwallet/utilities/text_styles.dart'; // import 'package:stackwallet/widgets/background.dart'; // import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; @@ -163,7 +163,7 @@ // // @override // Widget build(BuildContext context) { -// final Coin coin = ref.watch(managerProvider.select((value) => value.coin)); +// final CryptoCurrency coin = ref.watch(managerProvider.select((value) => value.coin)); // final wallet = ref.watch(walletsChangeNotifierProvider // .select((value) => value.getWallet(widget.walletId))); // diff --git a/lib/pages/ordinals/ordinal_details_view.dart b/lib/pages/ordinals/ordinal_details_view.dart index 590bca266..995c8fbb7 100644 --- a/lib/pages/ordinals/ordinal_details_view.dart +++ b/lib/pages/ordinals/ordinal_details_view.dart @@ -19,7 +19,6 @@ import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount_formatter.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/show_loading.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; @@ -30,10 +29,10 @@ import 'package:stackwallet/widgets/rounded_white_container.dart'; class OrdinalDetailsView extends ConsumerStatefulWidget { const OrdinalDetailsView({ - Key? key, + super.key, required this.walletId, required this.ordinal, - }) : super(key: key); + }); final String walletId; final Ordinal ordinal; @@ -113,7 +112,7 @@ class _OrdinalDetailsViewState extends ConsumerState<OrdinalDetailsView> { : ref.watch(pAmountFormatter(coin)).format( Amount( rawValue: BigInt.from(utxo!.value), - fractionDigits: coin.decimals, + fractionDigits: coin.fractionDigits, ), ), ), diff --git a/lib/pages/paynym/dialogs/confirm_paynym_connect_dialog.dart b/lib/pages/paynym/dialogs/confirm_paynym_connect_dialog.dart index ae5bfed00..6c53e5370 100644 --- a/lib/pages/paynym/dialogs/confirm_paynym_connect_dialog.dart +++ b/lib/pages/paynym/dialogs/confirm_paynym_connect_dialog.dart @@ -15,9 +15,9 @@ import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount_formatter.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/desktop/desktop_dialog.dart'; import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart'; import 'package:stackwallet/widgets/desktop/primary_button.dart'; @@ -26,19 +26,19 @@ import 'package:stackwallet/widgets/stack_dialog.dart'; class ConfirmPaynymConnectDialog extends ConsumerWidget { const ConfirmPaynymConnectDialog({ - Key? key, + super.key, required this.nymName, required this.locale, required this.onConfirmPressed, required this.amount, required this.coin, - }) : super(key: key); + }); final String nymName; final String locale; final VoidCallback onConfirmPressed; final Amount amount; - final Coin coin; + final CryptoCurrency coin; String get title => "Connect to $nymName"; diff --git a/lib/pages/paynym/dialogs/paynym_details_popup.dart b/lib/pages/paynym/dialogs/paynym_details_popup.dart index f5f970d38..922b775c3 100644 --- a/lib/pages/paynym/dialogs/paynym_details_popup.dart +++ b/lib/pages/paynym/dialogs/paynym_details_popup.dart @@ -28,7 +28,6 @@ import 'package:stackwallet/providers/global/wallets_provider.dart'; import 'package:stackwallet/route_generator.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; import 'package:stackwallet/wallets/models/tx_data.dart'; @@ -44,10 +43,10 @@ import 'package:tuple/tuple.dart'; class PaynymDetailsPopup extends ConsumerStatefulWidget { const PaynymDetailsPopup({ - Key? key, + super.key, required this.walletId, required this.accountLite, - }) : super(key: key); + }); final String walletId; final PaynymAccountLite accountLite; diff --git a/lib/pages/paynym/subwidgets/desktop_paynym_details.dart b/lib/pages/paynym/subwidgets/desktop_paynym_details.dart index c09baca9d..48a8a3684 100644 --- a/lib/pages/paynym/subwidgets/desktop_paynym_details.dart +++ b/lib/pages/paynym/subwidgets/desktop_paynym_details.dart @@ -26,7 +26,7 @@ import 'package:stackwallet/providers/global/locale_provider.dart'; import 'package:stackwallet/providers/global/wallets_provider.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; + import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; import 'package:stackwallet/wallets/models/tx_data.dart'; diff --git a/lib/pages/pinpad_views/lock_screen_view.dart b/lib/pages/pinpad_views/lock_screen_view.dart index e4ecb85a4..17d405206 100644 --- a/lib/pages/pinpad_views/lock_screen_view.dart +++ b/lib/pages/pinpad_views/lock_screen_view.dart @@ -23,7 +23,7 @@ import 'package:stackwallet/themes/stack_colors.dart'; // import 'package:stackwallet/providers/global/should_show_lockscreen_on_resume_state_provider.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/biometrics.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; + import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'; import 'package:stackwallet/utilities/show_loading.dart'; import 'package:stackwallet/utilities/text_styles.dart'; diff --git a/lib/pages/receive_view/addresses/address_card.dart b/lib/pages/receive_view/addresses/address_card.dart index 51e1402a3..9489712a4 100644 --- a/lib/pages/receive_view/addresses/address_card.dart +++ b/lib/pages/receive_view/addresses/address_card.dart @@ -30,9 +30,9 @@ import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/address_utils.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/conditional_parent.dart'; import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart'; import 'package:stackwallet/widgets/custom_buttons/simple_edit_button.dart'; @@ -53,7 +53,7 @@ class AddressCard extends ConsumerStatefulWidget { final int addressId; final String walletId; - final Coin coin; + final CryptoCurrency coin; final ClipboardInterface clipboard; final VoidCallback? onPressed; diff --git a/lib/pages/receive_view/addresses/address_details_view.dart b/lib/pages/receive_view/addresses/address_details_view.dart index 6da7be3c9..341bc4e8a 100644 --- a/lib/pages/receive_view/addresses/address_details_view.dart +++ b/lib/pages/receive_view/addresses/address_details_view.dart @@ -23,7 +23,6 @@ import 'package:stackwallet/providers/db/main_db_provider.dart'; import 'package:stackwallet/providers/global/wallets_provider.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/address_utils.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; @@ -40,10 +39,10 @@ import 'package:stackwallet/widgets/transaction_card.dart'; class AddressDetailsView extends ConsumerStatefulWidget { const AddressDetailsView({ - Key? key, + super.key, required this.addressId, required this.walletId, - }) : super(key: key); + }); static const String routeName = "/addressDetailsView"; @@ -398,7 +397,11 @@ class _AddressDetailsViewState extends ConsumerState<AddressDetailsView> { height: 12, ), if (!isDesktop) - coin == Coin.bitcoincash || coin == Coin.bitcoincashTestnet + ref + .watch(pWallets) + .getWallet(widget.walletId) + .isarTransactionVersion == + 2 ? _AddressDetailsTxV2List( walletId: widget.walletId, address: address, @@ -418,10 +421,10 @@ class _AddressDetailsViewState extends ConsumerState<AddressDetailsView> { class _AddressDetailsTxList extends StatelessWidget { const _AddressDetailsTxList({ - Key? key, + super.key, required this.walletId, required this.address, - }) : super(key: key); + }); final String walletId; final Address address; diff --git a/lib/pages/receive_view/addresses/address_qr_popup.dart b/lib/pages/receive_view/addresses/address_qr_popup.dart index 6e0c2e15b..c5ff43576 100644 --- a/lib/pages/receive_view/addresses/address_qr_popup.dart +++ b/lib/pages/receive_view/addresses/address_qr_popup.dart @@ -25,23 +25,23 @@ import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/address_utils.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/desktop/primary_button.dart'; import 'package:stackwallet/widgets/desktop/secondary_button.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; class AddressQrPopup extends StatefulWidget { const AddressQrPopup({ - Key? key, + super.key, required this.addressString, required this.coin, this.clipboard = const ClipboardWrapper(), - }) : super(key: key); + }); final String addressString; - final Coin coin; + final CryptoCurrency coin; final ClipboardInterface clipboard; @override @@ -54,12 +54,12 @@ class _AddressQrPopupState extends State<AddressQrPopup> { Future<void> _capturePng(bool shouldSaveInsteadOfShare) async { try { - RenderRepaintBoundary boundary = + final RenderRepaintBoundary boundary = _qrKey.currentContext?.findRenderObject() as RenderRepaintBoundary; - ui.Image image = await boundary.toImage(); - ByteData? byteData = + final ui.Image image = await boundary.toImage(); + final ByteData? byteData = await image.toByteData(format: ui.ImageByteFormat.png); - Uint8List pngBytes = byteData!.buffer.asUint8List(); + final Uint8List pngBytes = byteData!.buffer.asUint8List(); if (shouldSaveInsteadOfShare) { if (isDesktop) { diff --git a/lib/pages/receive_view/generate_receiving_uri_qr_code_view.dart b/lib/pages/receive_view/generate_receiving_uri_qr_code_view.dart index 4fd9d0cf1..6b9b228b6 100644 --- a/lib/pages/receive_view/generate_receiving_uri_qr_code_view.dart +++ b/lib/pages/receive_view/generate_receiving_uri_qr_code_view.dart @@ -28,10 +28,12 @@ import 'package:stackwallet/utilities/address_utils.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/bitcoincash.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/ecash.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/background.dart'; import 'package:stackwallet/widgets/conditional_parent.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; @@ -45,15 +47,15 @@ import 'package:stackwallet/widgets/textfield_icon_button.dart'; class GenerateUriQrCodeView extends StatefulWidget { const GenerateUriQrCodeView({ - Key? key, + super.key, required this.coin, required this.receivingAddress, this.clipboard = const ClipboardWrapper(), - }) : super(key: key); + }); static const String routeName = "/generateUriQrCodeView"; - final Coin coin; + final CryptoCurrency coin; final String receivingAddress; final ClipboardInterface clipboard; @@ -76,12 +78,12 @@ class _GenerateUriQrCodeViewState extends State<GenerateUriQrCodeView> { Future<void> _capturePng(bool shouldSaveInsteadOfShare) async { try { - RenderRepaintBoundary boundary = + final RenderRepaintBoundary boundary = _qrKey.currentContext?.findRenderObject() as RenderRepaintBoundary; - ui.Image image = await boundary.toImage(); - ByteData? byteData = + final ui.Image image = await boundary.toImage(); + final ByteData? byteData = await image.toByteData(format: ui.ImageByteFormat.png); - Uint8List pngBytes = byteData!.buffer.asUint8List(); + final Uint8List pngBytes = byteData!.buffer.asUint8List(); if (shouldSaveInsteadOfShare) { if (Util.isDesktop) { @@ -149,7 +151,7 @@ class _GenerateUriQrCodeViewState extends State<GenerateUriQrCodeView> { return null; } - Map<String, String> queryParams = {}; + final Map<String, String> queryParams = {}; if (amountString.isNotEmpty) { queryParams["amount"] = amountString; @@ -159,9 +161,7 @@ class _GenerateUriQrCodeViewState extends State<GenerateUriQrCodeView> { } String receivingAddress = widget.receivingAddress; - if ((widget.coin == Coin.bitcoincash || - widget.coin == Coin.eCash || - widget.coin == Coin.bitcoincashTestnet) && + if ((widget.coin is Bitcoincash || widget.coin is Ecash) && receivingAddress.contains(":")) { // remove cash addr prefix receivingAddress = receivingAddress.split(":").sublist(1).join(); @@ -256,9 +256,7 @@ class _GenerateUriQrCodeViewState extends State<GenerateUriQrCodeView> { isDesktop = Util.isDesktop; String receivingAddress = widget.receivingAddress; - if ((widget.coin == Coin.bitcoincash || - widget.coin == Coin.eCash || - widget.coin == Coin.bitcoincashTestnet) && + if ((widget.coin is Bitcoincash || widget.coin is Ecash) && receivingAddress.contains(":")) { // remove cash addr prefix receivingAddress = receivingAddress.split(":").sublist(1).join(); diff --git a/lib/pages/receive_view/receive_view.dart b/lib/pages/receive_view/receive_view.dart index f96e83274..c2bc6f979 100644 --- a/lib/pages/receive_view/receive_view.dart +++ b/lib/pages/receive_view/receive_view.dart @@ -29,9 +29,9 @@ import 'package:stackwallet/utilities/address_utils.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; import 'package:stackwallet/wallets/wallet/impl/bitcoin_wallet.dart'; import 'package:stackwallet/wallets/wallet/intermediate/bip39_hd_wallet.dart'; @@ -66,7 +66,7 @@ class ReceiveView extends ConsumerStatefulWidget { } class _ReceiveViewState extends ConsumerState<ReceiveView> { - late final Coin coin; + late final CryptoCurrency coin; late final String walletId; late final ClipboardInterface clipboard; late final bool _supportsSpark; diff --git a/lib/pages/send_view/confirm_transaction_view.dart b/lib/pages/send_view/confirm_transaction_view.dart index e9063d328..daedd54e6 100644 --- a/lib/pages/send_view/confirm_transaction_view.dart +++ b/lib/pages/send_view/confirm_transaction_view.dart @@ -32,9 +32,10 @@ import 'package:stackwallet/themes/theme_providers.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount_formatter.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/epiccash.dart'; +import 'package:stackwallet/wallets/crypto_currency/intermediate/nano_currency.dart'; import 'package:stackwallet/wallets/isar/providers/eth/current_token_wallet_provider.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; import 'package:stackwallet/wallets/models/tx_data.dart'; @@ -55,7 +56,7 @@ import 'package:stackwallet/widgets/textfield_icon_button.dart'; class ConfirmTransactionView extends ConsumerStatefulWidget { const ConfirmTransactionView({ - Key? key, + super.key, required this.txData, required this.walletId, required this.onSuccess, @@ -65,7 +66,7 @@ class ConfirmTransactionView extends ConsumerStatefulWidget { this.isPaynymNotificationTransaction = false, this.isTokenTx = false, this.onSuccessInsteadOfRouteOnSuccess, - }) : super(key: key); + }); static const String routeName = "/confirmTransactionView"; @@ -157,7 +158,7 @@ class _ConfirmTransactionViewState break; } } else { - if (coin == Coin.epicCash) { + if (coin is Epiccash) { txDataFuture = wallet.confirmSend( txData: widget.txData.copyWith( noteOnChain: onChainNoteController.text, @@ -276,7 +277,7 @@ class _ConfirmTransactionViewState ), ), ], - ) + ), ], ), ), @@ -292,9 +293,10 @@ class _ConfirmTransactionViewState child: Text( "Ok", style: STextStyles.button(context).copyWith( - color: Theme.of(context) - .extension<StackColors>()! - .accentColorDark), + color: Theme.of(context) + .extension<StackColors>()! + .accentColorDark, + ), ), onPressed: () { Navigator.of(context).pop(); @@ -340,7 +342,8 @@ class _ConfirmTransactionViewState final String unit; if (widget.isTokenTx) { unit = ref.watch( - pCurrentTokenWallet.select((value) => value!.tokenContract.symbol)); + pCurrentTokenWallet.select((value) => value!.tokenContract.symbol), + ); } else { unit = coin.ticker; } @@ -375,10 +378,12 @@ class _ConfirmTransactionViewState fee = widget.txData.fee; amountWithoutChange = (widget.txData.amountWithoutChange ?? Amount.zeroWith( - fractionDigits: wallet.cryptoCurrency.fractionDigits)) + + fractionDigits: wallet.cryptoCurrency.fractionDigits, + )) + (widget.txData.amountSparkWithoutChange ?? Amount.zeroWith( - fractionDigits: wallet.cryptoCurrency.fractionDigits)); + fractionDigits: wallet.cryptoCurrency.fractionDigits, + )); break; } } else { @@ -526,11 +531,11 @@ class _ConfirmTransactionViewState ], ), ), - if (coin != Coin.banano && coin != Coin.nano) + if (coin is! NanoCurrency) const SizedBox( height: 12, ), - if (coin != Coin.banano && coin != Coin.nano) + if (coin is! NanoCurrency) RoundedWhiteContainer( child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -570,13 +575,11 @@ class _ConfirmTransactionViewState ], ), ), - if (coin == Coin.epicCash && - widget.txData.noteOnChain!.isNotEmpty) + if (coin is Epiccash && widget.txData.noteOnChain!.isNotEmpty) const SizedBox( height: 12, ), - if (coin == Coin.epicCash && - widget.txData.noteOnChain!.isNotEmpty) + if (coin is Epiccash && widget.txData.noteOnChain!.isNotEmpty) RoundedWhiteContainer( child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, @@ -605,7 +608,7 @@ class _ConfirmTransactionViewState crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text( - (coin == Coin.epicCash) ? "Local Note" : "Note", + (coin is Epiccash) ? "Local Note" : "Note", style: STextStyles.smallMed12(context), ), const SizedBox( @@ -688,7 +691,8 @@ class _ConfirmTransactionViewState Text( "Amount", style: STextStyles.desktopTextExtraExtraSmall( - context), + context, + ), ), const SizedBox( height: 2, @@ -696,15 +700,18 @@ class _ConfirmTransactionViewState Builder( builder: (context) { final externalCalls = ref.watch( - prefsChangeNotifierProvider.select( - (value) => value.externalCalls)); + prefsChangeNotifierProvider.select( + (value) => value.externalCalls, + ), + ); String fiatAmount = "N/A"; if (externalCalls) { final price = widget.isTokenTx ? ref .read( - priceAnd24hChangeNotifierProvider) + priceAnd24hChangeNotifierProvider, + ) .getTokenPrice( ref .read(pCurrentTokenWallet)! @@ -714,7 +721,8 @@ class _ConfirmTransactionViewState .item1 : ref .read( - priceAnd24hChangeNotifierProvider) + priceAnd24hChangeNotifierProvider, + ) .getPrice(coin) .item1; if (price > Decimal.zero) { @@ -724,7 +732,8 @@ class _ConfirmTransactionViewState .fiatString( locale: ref .read( - localeServiceChangeNotifierProvider) + localeServiceChangeNotifierProvider, + ) .locale, ); } @@ -734,14 +743,15 @@ class _ConfirmTransactionViewState children: [ SelectableText( ref.watch(pAmountFormatter(coin)).format( - amountWithoutChange, - ethContract: ref - .read(pCurrentTokenWallet) - ?.tokenContract), + amountWithoutChange, + ethContract: ref + .read(pCurrentTokenWallet) + ?.tokenContract, + ), style: STextStyles - .desktopTextExtraExtraSmall( - context) - .copyWith( + .desktopTextExtraExtraSmall( + context, + ).copyWith( color: Theme.of(context) .extension<StackColors>()! .textDark, @@ -752,16 +762,20 @@ class _ConfirmTransactionViewState " | ", style: STextStyles .desktopTextExtraExtraSmall( - context), + context, + ), ), if (externalCalls) SelectableText( - "~$fiatAmount ${ref.watch(prefsChangeNotifierProvider.select( - (value) => value.currency, - ))}", + "~$fiatAmount ${ref.watch( + prefsChangeNotifierProvider.select( + (value) => value.currency, + ), + )}", style: STextStyles .desktopTextExtraExtraSmall( - context), + context, + ), ), ], ); @@ -787,7 +801,8 @@ class _ConfirmTransactionViewState ? "PayNym recipient" : "Send to", style: STextStyles.desktopTextExtraExtraSmall( - context), + context, + ), ), const SizedBox( height: 2, @@ -800,13 +815,13 @@ class _ConfirmTransactionViewState widget.txData.sparkRecipients!.first .address, style: STextStyles.desktopTextExtraExtraSmall( - context) - .copyWith( + context, + ).copyWith( color: Theme.of(context) .extension<StackColors>()! .textDark, ), - ) + ), ], ), ), @@ -827,7 +842,8 @@ class _ConfirmTransactionViewState Text( "Transaction fee", style: STextStyles.desktopTextExtraExtraSmall( - context), + context, + ), ), const SizedBox( height: 2, @@ -835,8 +851,8 @@ class _ConfirmTransactionViewState SelectableText( ref.watch(pAmountFormatter(coin)).format(fee!), style: STextStyles.desktopTextExtraExtraSmall( - context) - .copyWith( + context, + ).copyWith( color: Theme.of(context) .extension<StackColors>()! .textDark, @@ -892,17 +908,17 @@ class _ConfirmTransactionViewState mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - if (coin == Coin.epicCash) + if (coin is Epiccash) Text( "On chain Note (optional)", style: STextStyles.smallMed12(context), textAlign: TextAlign.left, ), - if (coin == Coin.epicCash) + if (coin is Epiccash) const SizedBox( height: 8, ), - if (coin == Coin.epicCash) + if (coin is Epiccash) ClipRRect( borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, @@ -942,12 +958,12 @@ class _ConfirmTransactionViewState ), ), ), - if (coin == Coin.epicCash) + if (coin is Epiccash) const SizedBox( height: 12, ), SelectableText( - (coin == Coin.epicCash) + (coin is Epiccash) ? "Local Note (optional)" : "Note (optional)", style: @@ -1016,7 +1032,7 @@ class _ConfirmTransactionViewState ), const SizedBox( height: 20, - ) + ), ], ), ), @@ -1221,11 +1237,12 @@ class _ConfirmTransactionViewState } else { unawaited( showFloatingFlushBar( - type: FlushBarType.warning, - message: Util.isDesktop - ? "Invalid passphrase" - : "Invalid PIN", - context: context), + type: FlushBarType.warning, + message: Util.isDesktop + ? "Invalid passphrase" + : "Invalid PIN", + context: context, + ), ); } } diff --git a/lib/pages/send_view/frost_ms/frost_send_view.dart b/lib/pages/send_view/frost_ms/frost_send_view.dart index ccaf5452e..8397a2449 100644 --- a/lib/pages/send_view/frost_ms/frost_send_view.dart +++ b/lib/pages/send_view/frost_ms/frost_send_view.dart @@ -25,10 +25,10 @@ import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount_formatter.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/show_loading.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; import 'package:stackwallet/wallets/models/tx_data.dart'; import 'package:stackwallet/wallets/wallet/impl/bitcoin_frost_wallet.dart'; @@ -58,7 +58,7 @@ class FrostSendView extends ConsumerStatefulWidget { static const String routeName = "/frostSendView"; final String walletId; - final Coin coin; + final CryptoCurrency coin; @override ConsumerState<FrostSendView> createState() => _FrostSendViewState(); @@ -69,7 +69,7 @@ class _FrostSendViewState extends ConsumerState<FrostSendView> { int _greatestWidgetIndex = 0; late final String walletId; - late final Coin coin; + late final CryptoCurrency coin; late TextEditingController noteController; late TextEditingController onChainNoteController; diff --git a/lib/pages/send_view/frost_ms/recipient.dart b/lib/pages/send_view/frost_ms/recipient.dart index 043f080f6..1f6c0514a 100644 --- a/lib/pages/send_view/frost_ms/recipient.dart +++ b/lib/pages/send_view/frost_ms/recipient.dart @@ -12,10 +12,10 @@ import 'package:stackwallet/utilities/amount/amount_unit.dart'; import 'package:stackwallet/utilities/barcode_scanner_interface.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart'; import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.dart'; import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart'; @@ -55,7 +55,7 @@ class Recipient extends ConsumerStatefulWidget { final int index; final int displayNumber; - final Coin coin; + final CryptoCurrency coin; final VoidCallback? remove; final VoidCallback? onChanged; @@ -324,7 +324,8 @@ class _RecipientState extends ConsumerState<Recipient> { final Amount amount = Decimal.parse(results["amount"]!) .toAmount( - fractionDigits: widget.coin.decimals, + fractionDigits: + widget.coin.fractionDigits, ); amountController.text = ref .read(pAmountFormatter(widget.coin)) @@ -409,7 +410,7 @@ class _RecipientState extends ConsumerState<Recipient> { textAlign: TextAlign.right, inputFormatters: [ AmountInputFormatter( - decimals: widget.coin.decimals, + decimals: widget.coin.fractionDigits, unit: ref.watch(pAmountUnit(widget.coin)), locale: locale, ), diff --git a/lib/pages/send_view/frost_ms/send_steps/frost_send_step_4.dart b/lib/pages/send_view/frost_ms/send_steps/frost_send_step_4.dart index 2267e7226..424229a2f 100644 --- a/lib/pages/send_view/frost_ms/send_steps/frost_send_step_4.dart +++ b/lib/pages/send_view/frost_ms/send_steps/frost_send_step_4.dart @@ -11,7 +11,6 @@ import 'package:stackwallet/providers/global/wallets_provider.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/amount/amount_formatter.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/show_loading.dart'; import 'package:stackwallet/utilities/text_styles.dart'; @@ -93,7 +92,7 @@ class _FrostSendStep4State extends ConsumerState<FrostSendStep4> { height: 12, ), Text( - "Send ${cryptoCurrency.coin.ticker}", + "Send ${cryptoCurrency.ticker}", style: STextStyles.w600_20(context), ), const SizedBox( @@ -103,7 +102,7 @@ class _FrostSendStep4State extends ConsumerState<FrostSendStep4> { ? _Recipient( address: recipients[0].address, amount: ref - .watch(pAmountFormatter(cryptoCurrency.coin)) + .watch(pAmountFormatter(cryptoCurrency)) .format(recipients[0].amount), ) : Column( @@ -143,7 +142,7 @@ class _FrostSendStep4State extends ConsumerState<FrostSendStep4> { body: _Recipient( address: recipients[i].address, amount: ref - .watch(pAmountFormatter(cryptoCurrency.coin)) + .watch(pAmountFormatter(cryptoCurrency)) .format(recipients[i].amount), ), ), @@ -156,7 +155,7 @@ class _FrostSendStep4State extends ConsumerState<FrostSendStep4> { DetailItem( title: "Transaction fee", detail: ref - .watch(pAmountFormatter(cryptoCurrency.coin)) + .watch(pAmountFormatter(cryptoCurrency)) .format(ref.watch(pFrostTxData)!.fee!), horizontal: true, ), @@ -165,7 +164,7 @@ class _FrostSendStep4State extends ConsumerState<FrostSendStep4> { ), DetailItem( title: "Total", - detail: ref.watch(pAmountFormatter(cryptoCurrency.coin)).format( + detail: ref.watch(pAmountFormatter(cryptoCurrency)).format( ref.watch(pFrostTxData)!.fee! + recipients.map((e) => e.amount).reduce((v, e) => v += e)), horizontal: true, diff --git a/lib/pages/send_view/send_view.dart b/lib/pages/send_view/send_view.dart index fc0b89dc3..803595178 100644 --- a/lib/pages/send_view/send_view.dart +++ b/lib/pages/send_view/send_view.dart @@ -43,13 +43,19 @@ import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/barcode_scanner_interface.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/prefs.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/epiccash.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/ethereum.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/monero.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/stellar.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/tezos.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; +import 'package:stackwallet/wallets/crypto_currency/intermediate/nano_currency.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; import 'package:stackwallet/wallets/models/tx_data.dart'; import 'package:stackwallet/wallets/wallet/impl/firo_wallet.dart'; @@ -73,19 +79,19 @@ import 'package:tuple/tuple.dart'; class SendView extends ConsumerStatefulWidget { const SendView({ - Key? key, + super.key, required this.walletId, required this.coin, this.autoFillData, this.clipboard = const ClipboardWrapper(), this.barcodeScanner = const BarcodeScannerWrapper(), this.accountLite, - }) : super(key: key); + }); static const String routeName = "/sendView"; final String walletId; - final Coin coin; + final CryptoCurrency coin; final SendViewAutoFillData? autoFillData; final ClipboardInterface clipboard; final BarcodeScannerInterface barcodeScanner; @@ -97,7 +103,7 @@ class SendView extends ConsumerStatefulWidget { class _SendViewState extends ConsumerState<SendView> { late final String walletId; - late final Coin coin; + late final CryptoCurrency coin; late final ClipboardInterface clipboard; late final BarcodeScannerInterface scanner; @@ -178,7 +184,7 @@ class _SendViewState extends ConsumerState<SendView> { // autofill amount field if (results["amount"] != null) { final Amount amount = Decimal.parse(results["amount"]!).toAmount( - fractionDigits: coin.decimals, + fractionDigits: coin.fractionDigits, ); cryptoAmountController.text = ref.read(pAmountFormatter(coin)).format( amount, @@ -232,15 +238,15 @@ class _SendViewState extends ConsumerState<SendView> { ref.read(priceAnd24hChangeNotifierProvider).getPrice(coin).item1; if (_price == Decimal.zero) { - amount = 0.toAmountAsRaw(fractionDigits: coin.decimals); + amount = 0.toAmountAsRaw(fractionDigits: coin.fractionDigits); } else { amount = baseAmount <= Amount.zero - ? 0.toAmountAsRaw(fractionDigits: coin.decimals) + ? 0.toAmountAsRaw(fractionDigits: coin.fractionDigits) : (baseAmount.decimal / _price) .toDecimal( - scaleOnInfinitePrecision: coin.decimals, + scaleOnInfinitePrecision: coin.fractionDigits, ) - .toAmount(fractionDigits: coin.decimals); + .toAmount(fractionDigits: coin.fractionDigits); } if (_cachedAmountToSend != null && _cachedAmountToSend == amount) { return; @@ -258,7 +264,7 @@ class _SendViewState extends ConsumerState<SendView> { cryptoAmountController.text = amountString; _cryptoAmountChangeLock = false; } else { - amount = 0.toAmountAsRaw(fractionDigits: coin.decimals); + amount = 0.toAmountAsRaw(fractionDigits: coin.fractionDigits); _cryptoAmountChangeLock = true; cryptoAmountController.text = ""; _cryptoAmountChangeLock = false; @@ -309,11 +315,11 @@ class _SendViewState extends ConsumerState<SendView> { _cryptoAmountChangedFeeUpdateTimer?.cancel(); _cryptoAmountChangedFeeUpdateTimer = Timer(updateFeesTimerDuration, () { - if (coin != Coin.epicCash && !_baseFocus.hasFocus) { + if (coin is! Epiccash && !_baseFocus.hasFocus) { setState(() { _calculateFeesFuture = calculateFees( amount == null - ? 0.toAmountAsRaw(fractionDigits: coin.decimals) + ? 0.toAmountAsRaw(fractionDigits: coin.fractionDigits) : amount!, ); }); @@ -330,11 +336,11 @@ class _SendViewState extends ConsumerState<SendView> { void _baseAmountChanged() { _baseAmountChangedFeeUpdateTimer?.cancel(); _baseAmountChangedFeeUpdateTimer = Timer(updateFeesTimerDuration, () { - if (coin != Coin.epicCash && !_cryptoFocus.hasFocus) { + if (coin is! Epiccash && !_cryptoFocus.hasFocus) { setState(() { _calculateFeesFuture = calculateFees( ref.read(pSendAmount) == null - ? 0.toAmountAsRaw(fractionDigits: coin.decimals) + ? 0.toAmountAsRaw(fractionDigits: coin.fractionDigits) : ref.read(pSendAmount)!, ); }); @@ -356,8 +362,8 @@ class _SendViewState extends ConsumerState<SendView> { final value = fee.contains(",") ? Decimal.parse(fee.replaceFirst(",", ".")) - .toAmount(fractionDigits: coin.decimals) - : Decimal.parse(fee).toAmount(fractionDigits: coin.decimals); + .toAmount(fractionDigits: coin.fractionDigits) + : Decimal.parse(fee).toAmount(fractionDigits: coin.fractionDigits); if (shouldSetState) { setState(() => _currentFee = value); @@ -455,7 +461,7 @@ class _SendViewState extends ConsumerState<SendView> { } Amount fee; - if (coin == Coin.monero) { + if (coin is Monero) { MoneroTransactionPriority specialMoneroId; switch (ref.read(feeRateTypeStateProvider.state).state) { case FeeRateType.fast: @@ -552,7 +558,7 @@ class _SendViewState extends ConsumerState<SendView> { final coinControlEnabled = ref.read(prefsChangeNotifierProvider).enableCoinControl; - if (coin != Coin.ethereum && + if (coin is! Ethereum && !(wallet is CoinControlInterface && coinControlEnabled) || (wallet is CoinControlInterface && coinControlEnabled && @@ -751,9 +757,7 @@ class _SendViewState extends ConsumerState<SendView> { break; } } else { - final memo = coin == Coin.stellar || coin == Coin.stellarTestnet - ? memoController.text - : null; + final memo = coin is Stellar ? memoController.text : null; txDataFuture = wallet.prepareSend( txData: TxData( recipients: [ @@ -878,16 +882,16 @@ class _SendViewState extends ConsumerState<SendView> { void initState() { coin = widget.coin; ref.refresh(feeSheetSessionCacheProvider); - _currentFee = 0.toAmountAsRaw(fractionDigits: coin.decimals); + _currentFee = 0.toAmountAsRaw(fractionDigits: coin.fractionDigits); _calculateFeesFuture = - calculateFees(0.toAmountAsRaw(fractionDigits: coin.decimals)); + calculateFees(0.toAmountAsRaw(fractionDigits: coin.fractionDigits)); _data = widget.autoFillData; walletId = widget.walletId; clipboard = widget.clipboard; scanner = widget.barcodeScanner; - isStellar = coin == Coin.stellar || coin == Coin.stellarTestnet; - isFiro = coin == Coin.firo || coin == Coin.firoTestNet; + isStellar = coin is Stellar; + isFiro = coin is Firo; sendToController = TextEditingController(); cryptoAmountController = TextEditingController(); @@ -905,7 +909,7 @@ class _SendViewState extends ConsumerState<SendView> { if (_data!.amount != null) { final amount = Amount.fromDecimal( _data!.amount!, - fractionDigits: coin.decimals, + fractionDigits: coin.fractionDigits, ); cryptoAmountController.text = ref.read(pAmountFormatter(coin)).format( @@ -927,7 +931,7 @@ class _SendViewState extends ConsumerState<SendView> { noteController.text = "PayNym send"; } - // if (coin != Coin.epicCash) { + // if (coin is! Epiccash) { // _cryptoFocus.addListener(() { // if (!_cryptoFocus.hasFocus && !_baseFocus.hasFocus) { // if (_amountToSend == null) { @@ -1005,8 +1009,8 @@ class _SendViewState extends ConsumerState<SendView> { ref.listen(publicPrivateBalanceStateProvider, (previous, next) { if (ref.read(pSendAmount) == null) { setState(() { - _calculateFeesFuture = - calculateFees(0.toAmountAsRaw(fractionDigits: coin.decimals)); + _calculateFeesFuture = calculateFees( + 0.toAmountAsRaw(fractionDigits: coin.fractionDigits)); }); } else { setState(() { @@ -1019,7 +1023,7 @@ class _SendViewState extends ConsumerState<SendView> { } // add listener for epic cash to strip http:// and https:// prefixes if the address also ocntains an @ symbol (indicating an epicbox address) - if (coin == Coin.epicCash) { + if (coin is Epiccash) { sendToController.addListener(() { _address = sendToController.text.trim(); @@ -1119,8 +1123,7 @@ class _SendViewState extends ConsumerState<SendView> { style: STextStyles.label(context) .copyWith(fontSize: 10), ), - if (coin != Coin.firo && - coin != Coin.firoTestNet) + if (coin is! Firo) Text( "Available balance", style: STextStyles.label(context) @@ -1233,7 +1236,7 @@ class _SendViewState extends ConsumerState<SendView> { style: STextStyles.smallMed12(context), textAlign: TextAlign.left, ), - // if (coin == Coin.monero) + // if (coin is Monero) // CustomTextButton( // text: "Use OpenAlias", // onTap: () async { @@ -1359,8 +1362,7 @@ class _SendViewState extends ConsumerState<SendView> { ); } - if (coin == - Coin.epicCash) { + if (coin is Epiccash) { // strip http:// and https:// if content contains @ content = formatAddress( content, @@ -1433,10 +1435,7 @@ class _SendViewState extends ConsumerState<SendView> { ), child: TextField( key: const Key("sendViewMemoFieldKey"), - maxLength: (coin == Coin.firo || - coin == Coin.firoTestNet) - ? 31 - : null, + maxLength: (coin is Firo) ? 31 : null, controller: memoController, readOnly: false, autocorrect: false, @@ -1527,7 +1526,8 @@ class _SendViewState extends ConsumerState<SendView> { _data!.contactLabel == _address) { error = SparkInterface.validateSparkAddress( address: _data!.address, - isTestNet: coin.isTestNet, + isTestNet: coin.network == + CryptoCurrencyNetwork.test, ) ? "Unsupported" : null; @@ -1733,7 +1733,7 @@ class _SendViewState extends ConsumerState<SendView> { style: STextStyles.smallMed12(context), textAlign: TextAlign.left, ), - if (coin != Coin.ethereum && coin != Coin.tezos) + if (coin is! Ethereum && coin is! Tezos) CustomTextButton( text: "Send all ${coin.ticker}", onTap: () async { @@ -1815,7 +1815,7 @@ class _SendViewState extends ConsumerState<SendView> { textAlign: TextAlign.right, inputFormatters: [ AmountInputFormatter( - decimals: coin.decimals, + decimals: coin.fractionDigits, unit: ref.watch(pAmountUnit(coin)), locale: locale, ), @@ -1825,7 +1825,7 @@ class _SendViewState extends ConsumerState<SendView> { // newValue) => // // RegExp(r'^([0-9]*[,.]?[0-9]{0,8}|[,.][0-9]{0,8})$') // // RegExp(r'^\d{1,3}([,\.]\d+)?|[,\.\d]+$') - // getAmountRegex(locale, coin.decimals) + // getAmountRegex(locale, coin.fractionDigits) // .hasMatch(newValue.text) // ? newValue // : oldValue), @@ -2001,17 +2001,17 @@ class _SendViewState extends ConsumerState<SendView> { const SizedBox( height: 12, ), - if (coin == Coin.epicCash) + if (coin is Epiccash) Text( "On chain Note (optional)", style: STextStyles.smallMed12(context), textAlign: TextAlign.left, ), - if (coin == Coin.epicCash) + if (coin is Epiccash) const SizedBox( height: 8, ), - if (coin == Coin.epicCash) + if (coin is Epiccash) ClipRRect( borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, @@ -2055,12 +2055,12 @@ class _SendViewState extends ConsumerState<SendView> { ), ), ), - if (coin == Coin.epicCash) + if (coin is Epiccash) const SizedBox( height: 12, ), Text( - (coin == Coin.epicCash) + (coin is Epiccash) ? "Local Note (optional)" : "Note (optional)", style: STextStyles.smallMed12(context), @@ -2111,26 +2111,23 @@ class _SendViewState extends ConsumerState<SendView> { const SizedBox( height: 12, ), - if (coin != Coin.epicCash && - coin != Coin.nano && - coin != Coin.banano && - coin != Coin.tezos) + if (coin is! Epiccash && + coin is! NanoCurrency && + coin is! Tezos) Text( "Transaction fee (estimated)", style: STextStyles.smallMed12(context), textAlign: TextAlign.left, ), - if (coin != Coin.epicCash && - coin != Coin.nano && - coin != Coin.banano && - coin != Coin.tezos) + if (coin is! Epiccash && + coin is! NanoCurrency && + coin is! Tezos) const SizedBox( height: 8, ), - if (coin != Coin.epicCash && - coin != Coin.nano && - coin != Coin.banano && - coin != Coin.tezos) + if (coin is! Epiccash && + coin is! NanoCurrency && + coin is! Tezos) Stack( children: [ TextField( @@ -2187,7 +2184,8 @@ class _SendViewState extends ConsumerState<SendView> { ?.decimal ?? Decimal.zero) .toAmount( - fractionDigits: coin.decimals, + fractionDigits: + coin.fractionDigits, ), updateChosen: (String fee) { if (fee == "custom") { diff --git a/lib/pages/send_view/sub_widgets/building_transaction_dialog.dart b/lib/pages/send_view/sub_widgets/building_transaction_dialog.dart index 8529925d6..112c33339 100644 --- a/lib/pages/send_view/sub_widgets/building_transaction_dialog.dart +++ b/lib/pages/send_view/sub_widgets/building_transaction_dialog.dart @@ -14,9 +14,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/themes/coin_image_provider.dart'; import 'package:stackwallet/themes/stack_colors.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/animated_widgets/rotating_arrows.dart'; import 'package:stackwallet/widgets/desktop/secondary_button.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; @@ -30,7 +30,7 @@ class BuildingTransactionDialog extends ConsumerStatefulWidget { }); final VoidCallback onCancel; - final Coin coin; + final CryptoCurrency coin; final bool isSpark; @override diff --git a/lib/pages/send_view/sub_widgets/sending_transaction_dialog.dart b/lib/pages/send_view/sub_widgets/sending_transaction_dialog.dart index 0376e9e3d..42f8ea47e 100644 --- a/lib/pages/send_view/sub_widgets/sending_transaction_dialog.dart +++ b/lib/pages/send_view/sub_widgets/sending_transaction_dialog.dart @@ -13,23 +13,23 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:lottie/lottie.dart'; -import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/themes/coin_image_provider.dart'; +import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/desktop/desktop_dialog.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; class SendingTransactionDialog extends ConsumerStatefulWidget { const SendingTransactionDialog({ - Key? key, + super.key, required this.coin, required this.controller, - }) : super(key: key); + }); - final Coin coin; + final CryptoCurrency coin; final ProgressAndSuccessController controller; @override diff --git a/lib/pages/send_view/sub_widgets/transaction_fee_selection_sheet.dart b/lib/pages/send_view/sub_widgets/transaction_fee_selection_sheet.dart index 8572d5037..e177c0f37 100644 --- a/lib/pages/send_view/sub_widgets/transaction_fee_selection_sheet.dart +++ b/lib/pages/send_view/sub_widgets/transaction_fee_selection_sheet.dart @@ -19,10 +19,14 @@ import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount_formatter.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/ethereum.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/monero.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/wownero.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/isar/providers/eth/current_token_wallet_provider.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; import 'package:stackwallet/wallets/wallet/impl/firo_wallet.dart'; @@ -44,12 +48,12 @@ class FeeSheetSessionCache extends ChangeNotifier { class TransactionFeeSelectionSheet extends ConsumerStatefulWidget { const TransactionFeeSelectionSheet({ - Key? key, + super.key, required this.walletId, required this.amount, required this.updateChosen, this.isToken = false, - }) : super(key: key); + }); final String walletId; final Amount amount; @@ -79,7 +83,7 @@ class _TransactionFeeSelectionSheetState required Amount amount, required FeeRateType feeRateType, required int feeRate, - required Coin coin, + required CryptoCurrency coin, }) async { switch (feeRateType) { case FeeRateType.fast: @@ -87,11 +91,13 @@ class _TransactionFeeSelectionSheetState if (widget.isToken == false) { final wallet = ref.read(pWallets).getWallet(walletId); - if (coin == Coin.monero || coin == Coin.wownero) { + if (coin is Monero || coin is Wownero) { final fee = await wallet.estimateFeeFor( - amount, MoneroTransactionPriority.fast.raw!); + amount, + MoneroTransactionPriority.fast.raw!, + ); ref.read(feeSheetSessionCacheProvider).fast[amount] = fee; - } else if (coin == Coin.firo || coin == Coin.firoTestNet) { + } else if (coin is Firo) { final Amount fee; switch (ref.read(publicPrivateBalanceStateProvider.state).state) { case FiroType.spark: @@ -122,11 +128,13 @@ class _TransactionFeeSelectionSheetState if (ref.read(feeSheetSessionCacheProvider).average[amount] == null) { if (widget.isToken == false) { final wallet = ref.read(pWallets).getWallet(walletId); - if (coin == Coin.monero || coin == Coin.wownero) { + if (coin is Monero || coin is Wownero) { final fee = await wallet.estimateFeeFor( - amount, MoneroTransactionPriority.regular.raw!); + amount, + MoneroTransactionPriority.regular.raw!, + ); ref.read(feeSheetSessionCacheProvider).average[amount] = fee; - } else if (coin == Coin.firo || coin == Coin.firoTestNet) { + } else if (coin is Firo) { final Amount fee; switch (ref.read(publicPrivateBalanceStateProvider.state).state) { case FiroType.spark: @@ -156,11 +164,13 @@ class _TransactionFeeSelectionSheetState if (ref.read(feeSheetSessionCacheProvider).slow[amount] == null) { if (widget.isToken == false) { final wallet = ref.read(pWallets).getWallet(walletId); - if (coin == Coin.monero || coin == Coin.wownero) { + if (coin is Monero || coin is Wownero) { final fee = await wallet.estimateFeeFor( - amount, MoneroTransactionPriority.slow.raw!); + amount, + MoneroTransactionPriority.slow.raw!, + ); ref.read(feeSheetSessionCacheProvider).slow[amount] = fee; - } else if (coin == Coin.firo || coin == Coin.firoTestNet) { + } else if (coin is Firo) { final Amount fee; switch (ref.read(publicPrivateBalanceStateProvider.state).state) { case FiroType.spark: @@ -192,10 +202,12 @@ class _TransactionFeeSelectionSheetState } String estimatedTimeToBeIncludedInNextBlock( - int targetBlockTime, int estimatedNumberOfBlocks) { - int time = targetBlockTime * estimatedNumberOfBlocks; + int targetBlockTime, + int estimatedNumberOfBlocks, + ) { + final int time = targetBlockTime * estimatedNumberOfBlocks; - int hours = (time / 3600).floor(); + final int hours = (time / 3600).floor(); if (hours > 1) { return "~$hours hours"; } else if (hours == 1) { @@ -295,7 +307,7 @@ class _TransactionFeeSelectionSheetState ref.read(feeRateTypeStateProvider.state).state = FeeRateType.fast; } - String? fee = + final String? fee = getAmount(FeeRateType.fast, wallet.info.coin); if (fee != null) { widget.updateChosen(fee); @@ -364,8 +376,10 @@ class _TransactionFeeSelectionSheetState feeRate: feeObject!.fast, amount: amount, ), - builder: (_, - AsyncSnapshot<Amount> snapshot) { + builder: ( + _, + AsyncSnapshot<Amount> snapshot, + ) { if (snapshot.connectionState == ConnectionState.done && snapshot.hasData) { @@ -380,7 +394,8 @@ class _TransactionFeeSelectionSheetState false, )})", style: STextStyles.itemSubtitle( - context), + context, + ), textAlign: TextAlign.left, ); } else { @@ -388,7 +403,8 @@ class _TransactionFeeSelectionSheetState stringsToLoopThrough: stringsToLoopThrough, style: STextStyles.itemSubtitle( - context), + context, + ), ); } }, @@ -398,19 +414,16 @@ class _TransactionFeeSelectionSheetState const SizedBox( height: 2, ), - if (feeObject == null && - coin != Coin.ethereum) + if (feeObject == null && coin is! Ethereum) AnimatedText( stringsToLoopThrough: stringsToLoopThrough, style: STextStyles.itemSubtitle(context), ), - if (feeObject != null && - coin != Coin.ethereum) + if (feeObject != null && coin is! Ethereum) Text( estimatedTimeToBeIncludedInNextBlock( - Constants.targetBlockTimeInSeconds( - coin), + coin.targetBlockTimeSeconds, feeObject!.numberOfBlocksFast, ), style: STextStyles.itemSubtitle(context), @@ -418,7 +431,7 @@ class _TransactionFeeSelectionSheetState ), ], ), - ) + ), ], ), ), @@ -434,7 +447,8 @@ class _TransactionFeeSelectionSheetState ref.read(feeRateTypeStateProvider.state).state = FeeRateType.average; } - String? fee = getAmount(FeeRateType.average, coin); + final String? fee = + getAmount(FeeRateType.average, coin); if (fee != null) { widget.updateChosen(fee); } @@ -500,8 +514,10 @@ class _TransactionFeeSelectionSheetState feeRate: feeObject!.medium, amount: amount, ), - builder: (_, - AsyncSnapshot<Amount> snapshot) { + builder: ( + _, + AsyncSnapshot<Amount> snapshot, + ) { if (snapshot.connectionState == ConnectionState.done && snapshot.hasData) { @@ -516,7 +532,8 @@ class _TransactionFeeSelectionSheetState false, )})", style: STextStyles.itemSubtitle( - context), + context, + ), textAlign: TextAlign.left, ); } else { @@ -524,7 +541,8 @@ class _TransactionFeeSelectionSheetState stringsToLoopThrough: stringsToLoopThrough, style: STextStyles.itemSubtitle( - context), + context, + ), ); } }, @@ -534,19 +552,16 @@ class _TransactionFeeSelectionSheetState const SizedBox( height: 2, ), - if (feeObject == null && - coin != Coin.ethereum) + if (feeObject == null && coin is! Ethereum) AnimatedText( stringsToLoopThrough: stringsToLoopThrough, style: STextStyles.itemSubtitle(context), ), - if (feeObject != null && - coin != Coin.ethereum) + if (feeObject != null && coin is! Ethereum) Text( estimatedTimeToBeIncludedInNextBlock( - Constants.targetBlockTimeInSeconds( - coin), + coin.targetBlockTimeSeconds, feeObject!.numberOfBlocksAverage, ), style: STextStyles.itemSubtitle(context), @@ -570,7 +585,7 @@ class _TransactionFeeSelectionSheetState ref.read(feeRateTypeStateProvider.state).state = FeeRateType.slow; } - String? fee = getAmount(FeeRateType.slow, coin); + final String? fee = getAmount(FeeRateType.slow, coin); if (fee != null) { widget.updateChosen(fee); } @@ -636,8 +651,10 @@ class _TransactionFeeSelectionSheetState feeRate: feeObject!.slow, amount: amount, ), - builder: (_, - AsyncSnapshot<Amount> snapshot) { + builder: ( + _, + AsyncSnapshot<Amount> snapshot, + ) { if (snapshot.connectionState == ConnectionState.done && snapshot.hasData) { @@ -652,7 +669,8 @@ class _TransactionFeeSelectionSheetState false, )})", style: STextStyles.itemSubtitle( - context), + context, + ), textAlign: TextAlign.left, ); } else { @@ -660,7 +678,8 @@ class _TransactionFeeSelectionSheetState stringsToLoopThrough: stringsToLoopThrough, style: STextStyles.itemSubtitle( - context), + context, + ), ); } }, @@ -670,19 +689,16 @@ class _TransactionFeeSelectionSheetState const SizedBox( height: 2, ), - if (feeObject == null && - coin != Coin.ethereum) + if (feeObject == null && coin is! Ethereum) AnimatedText( stringsToLoopThrough: stringsToLoopThrough, style: STextStyles.itemSubtitle(context), ), - if (feeObject != null && - coin != Coin.ethereum) + if (feeObject != null && coin is! Ethereum) Text( estimatedTimeToBeIncludedInNextBlock( - Constants.targetBlockTimeInSeconds( - coin), + coin.targetBlockTimeSeconds, feeObject!.numberOfBlocksSlow, ), style: STextStyles.itemSubtitle(context), @@ -732,7 +748,8 @@ class _TransactionFeeSelectionSheetState onChanged: (x) { ref .read( - feeRateTypeStateProvider.state) + feeRateTypeStateProvider.state, + ) .state = FeeRateType.custom; Navigator.of(context).pop(); }, @@ -781,7 +798,7 @@ class _TransactionFeeSelectionSheetState ); } - String? getAmount(FeeRateType feeRateType, Coin coin) { + String? getAmount(FeeRateType feeRateType, CryptoCurrency coin) { try { switch (feeRateType) { case FeeRateType.fast: diff --git a/lib/pages/send_view/token_send_view.dart b/lib/pages/send_view/token_send_view.dart index 028538d63..d537bc61a 100644 --- a/lib/pages/send_view/token_send_view.dart +++ b/lib/pages/send_view/token_send_view.dart @@ -34,12 +34,13 @@ import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/barcode_scanner_interface.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/prefs.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/epiccash.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/isar/providers/eth/current_token_wallet_provider.dart'; import 'package:stackwallet/wallets/isar/providers/eth/token_balance_provider.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; @@ -70,7 +71,7 @@ class TokenSendView extends ConsumerStatefulWidget { static const String routeName = "/tokenSendView"; final String walletId; - final Coin coin; + final CryptoCurrency coin; final EthContract tokenContract; final SendViewAutoFillData? autoFillData; final ClipboardInterface clipboard; @@ -82,7 +83,7 @@ class TokenSendView extends ConsumerStatefulWidget { class _TokenSendViewState extends ConsumerState<TokenSendView> { late final String walletId; - late final Coin coin; + late final CryptoCurrency coin; late final EthContract tokenContract; late final ClipboardInterface clipboard; late final BarcodeScannerInterface scanner; @@ -317,7 +318,7 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> { _cryptoAmountChangedFeeUpdateTimer?.cancel(); _cryptoAmountChangedFeeUpdateTimer = Timer(updateFeesTimerDuration, () { - if (coin != Coin.epicCash && !_baseFocus.hasFocus) { + if (coin is! Epiccash && !_baseFocus.hasFocus) { setState(() { _calculateFeesFuture = calculateFees(); }); @@ -329,7 +330,7 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> { void _baseAmountChanged() { _baseAmountChangedFeeUpdateTimer?.cancel(); _baseAmountChangedFeeUpdateTimer = Timer(updateFeesTimerDuration, () { - if (coin != Coin.epicCash && !_cryptoFocus.hasFocus) { + if (coin is! Epiccash && !_cryptoFocus.hasFocus) { setState(() { _calculateFeesFuture = calculateFees(); }); @@ -1161,7 +1162,7 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> { const SizedBox( height: 12, ), - if (coin != Coin.epicCash) + if (coin is! Epiccash) Text( "Transaction fee (estimated)", style: STextStyles.smallMed12(context), diff --git a/lib/pages/settings_views/global_settings_view/advanced_views/manage_coin_units/choose_unit_sheet.dart b/lib/pages/settings_views/global_settings_view/advanced_views/manage_coin_units/choose_unit_sheet.dart index d5ef002b7..ebacd1c77 100644 --- a/lib/pages/settings_views/global_settings_view/advanced_views/manage_coin_units/choose_unit_sheet.dart +++ b/lib/pages/settings_views/global_settings_view/advanced_views/manage_coin_units/choose_unit_sheet.dart @@ -4,16 +4,16 @@ import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/amount/amount_formatter.dart'; import 'package:stackwallet/utilities/amount/amount_unit.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; class ChooseUnitSheet extends ConsumerStatefulWidget { const ChooseUnitSheet({ - Key? key, + super.key, required this.coin, - }) : super(key: key); + }); - final Coin coin; + final CryptoCurrency coin; @override ConsumerState<ChooseUnitSheet> createState() => _ChooseUnitSheetState(); diff --git a/lib/pages/settings_views/global_settings_view/advanced_views/manage_coin_units/edit_coin_units_view.dart b/lib/pages/settings_views/global_settings_view/advanced_views/manage_coin_units/edit_coin_units_view.dart index bf06ebd2c..e68a96c69 100644 --- a/lib/pages/settings_views/global_settings_view/advanced_views/manage_coin_units/edit_coin_units_view.dart +++ b/lib/pages/settings_views/global_settings_view/advanced_views/manage_coin_units/edit_coin_units_view.dart @@ -9,9 +9,9 @@ import 'package:stackwallet/utilities/amount/amount_formatter.dart'; import 'package:stackwallet/utilities/amount/amount_unit.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/background.dart'; import 'package:stackwallet/widgets/conditional_parent.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; @@ -25,11 +25,11 @@ import 'package:stackwallet/widgets/textfield_icon_button.dart'; class EditCoinUnitsView extends ConsumerStatefulWidget { const EditCoinUnitsView({ - Key? key, + super.key, required this.coin, - }) : super(key: key); + }); - final Coin coin; + final CryptoCurrency coin; static const String routeName = "/editCoinUnitsView"; diff --git a/lib/pages/settings_views/global_settings_view/advanced_views/manage_coin_units/manage_coin_units_view.dart b/lib/pages/settings_views/global_settings_view/advanced_views/manage_coin_units/manage_coin_units_view.dart index f562b911e..7ec0656c1 100644 --- a/lib/pages/settings_views/global_settings_view/advanced_views/manage_coin_units/manage_coin_units_view.dart +++ b/lib/pages/settings_views/global_settings_view/advanced_views/manage_coin_units/manage_coin_units_view.dart @@ -5,12 +5,14 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/advanced_views/manage_coin_units/edit_coin_units_view.dart'; import 'package:stackwallet/providers/global/prefs_provider.dart'; +import 'package:stackwallet/supported_coins.dart'; import 'package:stackwallet/themes/coin_icon_provider.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/background.dart'; import 'package:stackwallet/widgets/conditional_parent.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; @@ -19,11 +21,11 @@ import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; class ManageCoinUnitsView extends ConsumerWidget { - const ManageCoinUnitsView({Key? key}) : super(key: key); + const ManageCoinUnitsView({super.key}); static const String routeName = "/manageCoinUnitsView"; - void onEditPressed(Coin coin, BuildContext context) { + void onEditPressed(CryptoCurrency coin, BuildContext context) { if (Util.isDesktop) { showDialog<void>( context: context, @@ -39,14 +41,17 @@ class ManageCoinUnitsView extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - bool showTestNet = ref.watch( + final showTestNet = ref.watch( prefsChangeNotifierProvider.select((value) => value.showTestNetCoins), ); - final _coins = Coin.values.where((e) => e != Coin.firoTestNet).toList(); + final _coins = SupportedCoins.cryptocurrencies + .where((e) => e is! Firo && e.network != CryptoCurrencyNetwork.test) + .toList(); - List<Coin> coins = - showTestNet ? _coins : _coins.where((e) => !e.isTestNet).toList(); + final coins = showTestNet + ? _coins + : _coins.where((e) => e.network != CryptoCurrencyNetwork.test).toList(); return ConditionalParent( condition: Util.isDesktop, diff --git a/lib/pages/settings_views/global_settings_view/advanced_views/manage_explorer_view.dart b/lib/pages/settings_views/global_settings_view/advanced_views/manage_explorer_view.dart index 9242731d1..5ebf47bd2 100644 --- a/lib/pages/settings_views/global_settings_view/advanced_views/manage_explorer_view.dart +++ b/lib/pages/settings_views/global_settings_view/advanced_views/manage_explorer_view.dart @@ -12,21 +12,21 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/block_explorers.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/background.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; class ManageExplorerView extends ConsumerStatefulWidget { const ManageExplorerView({ - Key? key, + super.key, required this.coin, - }) : super(key: key); + }); static const String routeName = "/manageExplorer"; - final Coin coin; + final CryptoCurrency coin; @override ConsumerState<ManageExplorerView> createState() => _ManageExplorerViewState(); diff --git a/lib/pages/settings_views/global_settings_view/hidden_settings.dart b/lib/pages/settings_views/global_settings_view/hidden_settings.dart index 6ebafad4a..fa0db26b0 100644 --- a/lib/pages/settings_views/global_settings_view/hidden_settings.dart +++ b/lib/pages/settings_views/global_settings_view/hidden_settings.dart @@ -19,8 +19,9 @@ import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/stellar.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/background.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/dialogs/tor_warning_dialog.dart'; @@ -74,42 +75,46 @@ class HiddenSettings extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - Consumer(builder: (_, ref, __) { - return GestureDetector( - onTap: () async { - final notifs = - ref.read(notificationsProvider).notifications; + Consumer( + builder: (_, ref, __) { + return GestureDetector( + onTap: () async { + final notifs = ref + .read(notificationsProvider) + .notifications; - for (final n in notifs) { + for (final n in notifs) { + await ref + .read(notificationsProvider) + .delete(n, false); + } await ref .read(notificationsProvider) - .delete(n, false); - } - await ref - .read(notificationsProvider) - .delete(notifs[0], true); + .delete(notifs[0], true); - if (context.mounted) { - unawaited( - showFloatingFlushBar( - type: FlushBarType.success, - message: "Notification history deleted", - context: context, - ), - ); - } - }, - child: RoundedWhiteContainer( - child: Text( - "Delete notifications", - style: STextStyles.button(context).copyWith( + if (context.mounted) { + unawaited( + showFloatingFlushBar( + type: FlushBarType.success, + message: "Notification history deleted", + context: context, + ), + ); + } + }, + child: RoundedWhiteContainer( + child: Text( + "Delete notifications", + style: STextStyles.button(context).copyWith( color: Theme.of(context) .extension<StackColors>()! - .accentColorDark), + .accentColorDark, + ), + ), ), - ), - ); - }), + ); + }, + ), // const SizedBox( // height: 12, // ), @@ -141,34 +146,37 @@ class HiddenSettings extends StatelessWidget { const SizedBox( height: 12, ), - Consumer(builder: (_, ref, __) { - return GestureDetector( - onTap: () async { - await ref - .read(debugServiceProvider) - .deleteAllLogs(); + Consumer( + builder: (_, ref, __) { + return GestureDetector( + onTap: () async { + await ref + .read(debugServiceProvider) + .deleteAllLogs(); - if (context.mounted) { - unawaited( - showFloatingFlushBar( - type: FlushBarType.success, - message: "Debug Logs deleted", - context: context, - ), - ); - } - }, - child: RoundedWhiteContainer( - child: Text( - "Delete Debug Logs", - style: STextStyles.button(context).copyWith( + if (context.mounted) { + unawaited( + showFloatingFlushBar( + type: FlushBarType.success, + message: "Debug Logs deleted", + context: context, + ), + ); + } + }, + child: RoundedWhiteContainer( + child: Text( + "Delete Debug Logs", + style: STextStyles.button(context).copyWith( color: Theme.of(context) .extension<StackColors>()! - .accentColorDark), + .accentColorDark, + ), + ), ), - ), - ); - }), + ); + }, + ), const SizedBox( height: 12, ), @@ -216,8 +224,10 @@ class HiddenSettings extends StatelessWidget { // ), Consumer( builder: (_, ref, __) { - if (ref.watch(prefsChangeNotifierProvider - .select((value) => value.familiarity)) < + if (ref.watch( + prefsChangeNotifierProvider + .select((value) => value.familiarity), + ) < 6) { return GestureDetector( onTap: () async { @@ -236,9 +246,10 @@ class HiddenSettings extends StatelessWidget { child: Text( "Enable exchange", style: STextStyles.button(context).copyWith( - color: Theme.of(context) - .extension<StackColors>()! - .accentColorDark), + color: Theme.of(context) + .extension<StackColors>()! + .accentColorDark, + ), ), ), ); @@ -257,7 +268,7 @@ class HiddenSettings extends StatelessWidget { await showDialog<bool>( context: context, builder: (_) => TorWarningDialog( - coin: Coin.stellar, + coin: Stellar(CryptoCurrencyNetwork.main), ), ); }, @@ -265,9 +276,10 @@ class HiddenSettings extends StatelessWidget { child: Text( "Show Tor warning popup", style: STextStyles.button(context).copyWith( - color: Theme.of(context) - .extension<StackColors>()! - .accentColorDark), + color: Theme.of(context) + .extension<StackColors>()! + .accentColorDark, + ), ), ), ); @@ -286,9 +298,10 @@ class HiddenSettings extends StatelessWidget { child: Text( "Do nothing", style: STextStyles.button(context).copyWith( - color: Theme.of(context) - .extension<StackColors>()! - .accentColorDark), + color: Theme.of(context) + .extension<StackColors>()! + .accentColorDark, + ), ), ), ); 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 7a656c288..87a354191 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 @@ -14,26 +14,23 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/flutter_svg.dart'; -import 'package:solana/solana.dart'; import 'package:stackwallet/models/node_model.dart'; import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/providers/global/secure_store_provider.dart'; import 'package:stackwallet/providers/providers.dart'; -import 'package:stackwallet/services/tor_service.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/connection_check/electrum_connection_check.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'; -import 'package:stackwallet/utilities/logger.dart'; -import 'package:stackwallet/utilities/test_epic_box_connection.dart'; -import 'package:stackwallet/utilities/test_eth_node_connection.dart'; -import 'package:stackwallet/utilities/test_monero_node_connection.dart'; -import 'package:stackwallet/utilities/test_stellar_node_connection.dart'; +import 'package:stackwallet/utilities/test_node_connection.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; -import 'package:stackwallet/wallets/api/tezos/tezos_rpc_api.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/epiccash.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/ethereum.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/monero.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/wownero.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; +import 'package:stackwallet/wallets/crypto_currency/intermediate/cryptonote_currency.dart'; import 'package:stackwallet/widgets/background.dart'; import 'package:stackwallet/widgets/conditional_parent.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; @@ -51,17 +48,17 @@ enum AddEditNodeViewType { add, edit } class AddEditNodeView extends ConsumerStatefulWidget { const AddEditNodeView({ - Key? key, + super.key, required this.viewType, required this.coin, required this.nodeId, required this.routeOnSuccessOrDelete, - }) : super(key: key); + }); static const String routeName = "/addEditNode"; final AddEditNodeViewType viewType; - final Coin coin; + final CryptoCurrency coin; final String routeOnSuccessOrDelete; final String? nodeId; @@ -71,192 +68,31 @@ class AddEditNodeView extends ConsumerStatefulWidget { class _AddEditNodeViewState extends ConsumerState<AddEditNodeView> { late final AddEditNodeViewType viewType; - late final Coin coin; + late final CryptoCurrency coin; late final String? nodeId; late final bool isDesktop; late bool saveEnabled; late bool testConnectionEnabled; - Future<bool> _xmrHelper(String url, int? port) async { - final uri = Uri.parse(url); - - final String path = uri.path.isEmpty ? "/json_rpc" : uri.path; - - final uriString = "${uri.scheme}://${uri.host}:${port ?? 0}$path"; - - ref.read(nodeFormDataProvider).useSSL = true; - - final response = await testMoneroNodeConnection( - Uri.parse(uriString), - false, - ); - - if (response.cert != null) { - if (mounted) { - final shouldAllowBadCert = await showBadX509CertificateDialog( - response.cert!, - response.url!, - response.port!, - context, - ); - - if (shouldAllowBadCert) { - final response = - await testMoneroNodeConnection(Uri.parse(uriString), true); - ref.read(nodeFormDataProvider).host = url; - return response.success; - } - } - } else { - ref.read(nodeFormDataProvider).host = url; - return response.success; + void _onTestSuccess(NodeFormData data) { + if (coin is Epiccash) { + ref.read(nodeFormDataProvider).host = data.host; + ref.read(nodeFormDataProvider).port = data.port; + ref.read(nodeFormDataProvider).useSSL = data.useSSL; + } else if (coin is CryptonoteCurrency) { + ref.read(nodeFormDataProvider).host = data.host; } - - return false; - } - - Future<bool> _testConnection({bool showFlushBar = true}) async { - final formData = ref.read(nodeFormDataProvider); - - bool testPassed = false; - - switch (coin) { - case Coin.epicCash: - try { - final data = await testEpicNodeConnection(formData); - - if (data != null) { - testPassed = true; - ref.read(nodeFormDataProvider).host = data.host; - ref.read(nodeFormDataProvider).port = data.port; - ref.read(nodeFormDataProvider).useSSL = data.useSSL; - } - } catch (e, s) { - Logging.instance.log("$e\n$s", level: LogLevel.Warning); - } - break; - - case Coin.monero: - case Coin.wownero: - try { - final url = formData.host!; - final uri = Uri.tryParse(url); - if (uri != null) { - if (!uri.hasScheme) { - // try https first - testPassed = await _xmrHelper("https://$url", formData.port); - - if (testPassed == false) { - // try http - testPassed = await _xmrHelper("http://$url", formData.port); - } - } else { - testPassed = await _xmrHelper(url, formData.port); - } - } - } catch (e, s) { - Logging.instance.log("$e\n$s", level: LogLevel.Warning); - } - - break; - - case Coin.bitcoin: - case Coin.bitcoincash: - case Coin.litecoin: - case Coin.dogecoin: - case Coin.eCash: - case Coin.firo: - case Coin.namecoin: - case Coin.particl: - case Coin.peercoin: - case Coin.peercoinTestNet: - case Coin.bitcoinFrost: - case Coin.bitcoinFrostTestNet: - case Coin.bitcoinTestNet: - case Coin.litecoinTestNet: - case Coin.bitcoincashTestnet: - case Coin.firoTestNet: - case Coin.dogecoinTestNet: - try { - testPassed = await checkElectrumServer( - host: formData.host!, - port: formData.port!, - useSSL: formData.useSSL!, - overridePrefs: ref.read(prefsChangeNotifierProvider), - overrideTorService: ref.read(pTorService), - ); - } catch (_) { - testPassed = false; - } - - break; - - case Coin.ethereum: - try { - testPassed = await testEthNodeConnection(formData.host!); - } catch (_) { - testPassed = false; - } - break; - - case Coin.stellar: - case Coin.stellarTestnet: - try { - testPassed = - await testStellarNodeConnection(formData.host!, formData.port!); - } catch (_) {} - break; - - case Coin.nano: - case Coin.banano: - throw UnimplementedError(); - //TODO: check network/node - case Coin.tezos: - try { - testPassed = await TezosRpcAPI.testNetworkConnection( - nodeInfo: (host: formData.host!, port: formData.port!), - ); - } catch (_) {} - break; - - case Coin.solana: - try { - RpcClient rpcClient; - if (formData.host!.startsWith("http") || - formData.host!.startsWith("https")) { - rpcClient = RpcClient("${formData.host}:${formData.port}"); - } else { - rpcClient = RpcClient("http://${formData.host}:${formData.port}"); - } - await rpcClient.getEpochInfo().then((value) => testPassed = true); - } catch (_) { - testPassed = false; - } - break; - } - - if (showFlushBar && mounted) { - if (testPassed) { - unawaited(showFloatingFlushBar( - type: FlushBarType.success, - message: "Server ping success", - context: context, - )); - } else { - unawaited(showFloatingFlushBar( - type: FlushBarType.warning, - message: "Server unreachable", - context: context, - )); - } - } - - return testPassed; } Future<void> attemptSave() async { - final canConnect = await _testConnection(showFlushBar: false); + final canConnect = await testNodeConnection( + context: context, + onSuccess: _onTestSuccess, + cryptoCurrency: coin, + nodeFormData: ref.read(nodeFormDataProvider), + ref: ref, + ); bool? shouldSave; @@ -387,7 +223,7 @@ class _AddEditNodeViewState extends ConsumerState<AddEditNodeView> { // strip unused path String address = formData.host!; - if (coin == Coin.monero || coin == Coin.wownero) { + if (coin is Monero || coin is Wownero) { if (address.startsWith("http")) { final uri = Uri.parse(address); address = "${uri.scheme}://${uri.host}"; @@ -404,7 +240,7 @@ class _AddEditNodeViewState extends ConsumerState<AddEditNodeView> { useSSL: formData.useSSL!, loginName: formData.login, enabled: true, - coinName: coin.name, + coinName: coin.identifier, isFailover: formData.isFailover!, trusted: formData.trusted!, isDown: false, @@ -429,7 +265,7 @@ class _AddEditNodeViewState extends ConsumerState<AddEditNodeView> { useSSL: formData.useSSL!, loginName: formData.login, enabled: true, - coinName: coin.name, + coinName: coin.identifier, isFailover: formData.isFailover!, trusted: formData.trusted!, isDown: false, @@ -652,7 +488,32 @@ class _AddEditNodeViewState extends ConsumerState<AddEditNodeView> { buttonHeight: isDesktop ? ButtonHeight.l : null, onPressed: testConnectionEnabled ? () async { - await _testConnection(); + final testPassed = await testNodeConnection( + context: context, + onSuccess: _onTestSuccess, + cryptoCurrency: coin, + nodeFormData: ref.read(nodeFormDataProvider), + ref: ref, + ); + if (context.mounted) { + if (testPassed) { + unawaited( + showFloatingFlushBar( + type: FlushBarType.success, + message: "Server ping success", + context: context, + ), + ); + } else { + unawaited( + showFloatingFlushBar( + type: FlushBarType.warning, + message: "Server unreachable", + context: context, + ), + ); + } + } } : null, ), @@ -724,7 +585,7 @@ class NodeForm extends ConsumerStatefulWidget { final NodeModel? node; final SecureStorageInterface secureStore; final bool readOnly; - final Coin coin; + final CryptoCurrency coin; final void Function(bool canSave, bool canTestConnection)? onChanged; @override @@ -754,39 +615,15 @@ class _NodeFormState extends ConsumerState<NodeForm> { void Function(bool canSave, bool canTestConnection)? onChanged; - bool _checkShouldEnableAuthFields(Coin coin) { + bool _checkShouldEnableAuthFields(CryptoCurrency coin) { // TODO: which coin servers can have username and password? switch (coin) { - case Coin.bitcoin: - case Coin.litecoin: - case Coin.dogecoin: - case Coin.firo: - case Coin.namecoin: - case Coin.bitcoincash: - case Coin.particl: - case Coin.peercoin: - case Coin.peercoinTestNet: - case Coin.tezos: - case Coin.bitcoinTestNet: - case Coin.litecoinTestNet: - case Coin.bitcoincashTestnet: - case Coin.firoTestNet: - case Coin.dogecoinTestNet: - case Coin.epicCash: - case Coin.nano: - case Coin.banano: - case Coin.eCash: - case Coin.solana: - case Coin.stellar: - case Coin.stellarTestnet: - case Coin.bitcoinFrost: - case Coin.bitcoinFrostTestNet: - return false; - - case Coin.ethereum: - case Coin.monero: - case Coin.wownero: + case Ethereum(): + case CryptonoteCurrency(): return true; + + default: + return false; } } @@ -862,7 +699,7 @@ class _NodeFormState extends ConsumerState<NodeForm> { _useSSL = node.useSSL; _isFailover = node.isFailover; _trusted = node.trusted ?? false; - if (widget.coin == Coin.epicCash) { + if (widget.coin is Epiccash) { enableSSLCheckbox = !node.host.startsWith("http"); } else { enableSSLCheckbox = true; @@ -961,9 +798,7 @@ class _NodeFormState extends ConsumerState<NodeForm> { focusNode: _hostFocusNode, style: STextStyles.field(context), decoration: standardInputDecoration( - (widget.coin != Coin.monero && widget.coin != Coin.wownero) - ? "IP address" - : "Url", + (widget.coin is! CryptonoteCurrency) ? "IP address" : "Url", _hostFocusNode, context, ).copyWith( @@ -987,7 +822,7 @@ class _NodeFormState extends ConsumerState<NodeForm> { : null, ), onChanged: (newValue) { - if (widget.coin == Coin.epicCash) { + if (widget.coin is Epiccash) { if (newValue.startsWith("https://")) { _useSSL = true; enableSSLCheckbox = false; @@ -1151,7 +986,7 @@ class _NodeFormState extends ConsumerState<NodeForm> { const SizedBox( height: 8, ), - if (widget.coin != Coin.monero && widget.coin != Coin.wownero) + if (widget.coin is! CryptonoteCurrency) Row( children: [ GestureDetector( @@ -1202,7 +1037,7 @@ class _NodeFormState extends ConsumerState<NodeForm> { ), ], ), - if (widget.coin == Coin.monero || widget.coin == Coin.wownero) + if (widget.coin is Monero || widget.coin is Wownero) Row( children: [ GestureDetector( @@ -1253,15 +1088,11 @@ class _NodeFormState extends ConsumerState<NodeForm> { ), ], ), - if (widget.coin != Coin.monero && - widget.coin != Coin.wownero && - widget.coin != Coin.epicCash) + if (widget.coin is! CryptonoteCurrency && widget.coin is! Epiccash) const SizedBox( height: 8, ), - if (widget.coin != Coin.monero && - widget.coin != Coin.wownero && - widget.coin != Coin.epicCash) + if (widget.coin is! CryptonoteCurrency && widget.coin is! Epiccash) Row( children: [ GestureDetector( diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/coin_nodes_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/coin_nodes_view.dart index 1bb393246..56b5538e5 100644 --- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/coin_nodes_view.dart +++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/coin_nodes_view.dart @@ -18,9 +18,9 @@ import 'package:stackwallet/pages/settings_views/sub_widgets/nodes_list.dart'; import 'package:stackwallet/themes/coin_icon_provider.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/background.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart'; @@ -30,14 +30,14 @@ import 'package:tuple/tuple.dart'; class CoinNodesView extends ConsumerStatefulWidget { const CoinNodesView({ - Key? key, + super.key, required this.coin, this.rootNavigator = false, - }) : super(key: key); + }); static const String routeName = "/coinNodes"; - final Coin coin; + final CryptoCurrency coin; final bool rootNavigator; @override diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/manage_nodes_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/manage_nodes_view.dart index c6e59c96c..74980942b 100644 --- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/manage_nodes_view.dart +++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/manage_nodes_view.dart @@ -15,19 +15,21 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/manage_nodes_views/coin_nodes_view.dart'; import 'package:stackwallet/providers/providers.dart'; +import 'package:stackwallet/supported_coins.dart'; import 'package:stackwallet/themes/coin_icon_provider.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/background.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; class ManageNodesView extends ConsumerStatefulWidget { const ManageNodesView({ - Key? key, - }) : super(key: key); + super.key, + }); static const String routeName = "/manageNodes"; @@ -36,12 +38,14 @@ class ManageNodesView extends ConsumerStatefulWidget { } class _ManageNodesViewState extends ConsumerState<ManageNodesView> { - List<Coin> _coins = [...Coin.values]; + List<CryptoCurrency> _coins = [...SupportedCoins.cryptocurrencies]; @override void initState() { _coins = _coins.toList(); - _coins.remove(Coin.firoTestNet); + _coins.removeWhere( + (e) => e is Firo && e.network == CryptoCurrencyNetwork.test, + ); super.initState(); } @@ -52,12 +56,13 @@ class _ManageNodesViewState extends ConsumerState<ManageNodesView> { @override Widget build(BuildContext context) { - bool showTestNet = ref.watch( + final showTestNet = ref.watch( prefsChangeNotifierProvider.select((value) => value.showTestNetCoins), ); - List<Coin> coins = - showTestNet ? _coins : _coins.where((e) => !e.isTestNet).toList(); + final coins = showTestNet + ? _coins + : _coins.where((e) => e.network != CryptoCurrencyNetwork.test).toList(); return Background( child: Scaffold( 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 1034d986c..8cb734e94 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 @@ -13,25 +13,17 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; -import 'package:solana/solana.dart'; import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart'; import 'package:stackwallet/providers/global/secure_store_provider.dart'; import 'package:stackwallet/providers/providers.dart'; -import 'package:stackwallet/services/tor_service.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/connection_check/electrum_connection_check.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'; -import 'package:stackwallet/utilities/logger.dart'; -import 'package:stackwallet/utilities/test_epic_box_connection.dart'; -import 'package:stackwallet/utilities/test_eth_node_connection.dart'; -import 'package:stackwallet/utilities/test_monero_node_connection.dart'; -import 'package:stackwallet/utilities/test_stellar_node_connection.dart'; +import 'package:stackwallet/utilities/test_node_connection.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; -import 'package:stackwallet/wallets/api/tezos/tezos_rpc_api.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/background.dart'; import 'package:stackwallet/widgets/conditional_parent.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; @@ -43,15 +35,15 @@ import 'package:tuple/tuple.dart'; class NodeDetailsView extends ConsumerStatefulWidget { const NodeDetailsView({ - Key? key, + super.key, required this.coin, required this.nodeId, required this.popRouteName, - }) : super(key: key); + }); static const String routeName = "/nodeDetails"; - final Coin coin; + final CryptoCurrency coin; final String nodeId; final String popRouteName; @@ -61,7 +53,7 @@ class NodeDetailsView extends ConsumerStatefulWidget { class _NodeDetailsViewState extends ConsumerState<NodeDetailsView> { late final SecureStorageInterface secureStore; - late final Coin coin; + late final CryptoCurrency coin; late final String nodeId; late final String popRouteName; @@ -76,170 +68,19 @@ class _NodeDetailsViewState extends ConsumerState<NodeDetailsView> { super.initState(); } - Future<void> _testConnection(WidgetRef ref, BuildContext context) async { - final node = - ref.watch(nodeServiceChangeNotifierProvider).getNodeById(id: nodeId); - - bool testPassed = false; - - switch (coin) { - case Coin.epicCash: - try { - testPassed = await testEpicNodeConnection( - NodeFormData() - ..host = node!.host - ..useSSL = node.useSSL - ..port = node.port, - ) != - null; - } catch (e, s) { - Logging.instance.log("$e\n$s", level: LogLevel.Warning); - testPassed = false; - } - break; - - case Coin.monero: - case Coin.wownero: - try { - final uri = Uri.parse(node!.host); - if (uri.scheme.startsWith("http")) { - final String path = uri.path.isEmpty ? "/json_rpc" : uri.path; - - String uriString = "${uri.scheme}://${uri.host}:${node.port}$path"; - - final response = await testMoneroNodeConnection( - Uri.parse(uriString), - false, - ); - - if (response.cert != null) { - if (mounted) { - final shouldAllowBadCert = await showBadX509CertificateDialog( - response.cert!, - response.url!, - response.port!, - context, - ); - - if (shouldAllowBadCert) { - final response = await testMoneroNodeConnection( - Uri.parse(uriString), true); - testPassed = response.success; - } - } - } else { - testPassed = response.success; - } - } - } catch (e, s) { - Logging.instance.log("$e\n$s", level: LogLevel.Warning); - } - - break; - - case Coin.bitcoin: - case Coin.litecoin: - case Coin.dogecoin: - case Coin.firo: - case Coin.particl: - case Coin.peercoin: - case Coin.peercoinTestNet: - case Coin.bitcoinTestNet: - case Coin.firoTestNet: - case Coin.dogecoinTestNet: - case Coin.bitcoincash: - case Coin.namecoin: - case Coin.litecoinTestNet: - case Coin.bitcoincashTestnet: - case Coin.eCash: - case Coin.bitcoinFrost: - case Coin.bitcoinFrostTestNet: - try { - testPassed = await checkElectrumServer( - host: node!.host, - port: node.port, - useSSL: node.useSSL, - overridePrefs: ref.read(prefsChangeNotifierProvider), - overrideTorService: ref.read(pTorService), - ); - } catch (_) { - testPassed = false; - } - - break; - - case Coin.ethereum: - try { - testPassed = await testEthNodeConnection(node!.host); - } catch (_) { - testPassed = false; - } - break; - - case Coin.nano: - case Coin.banano: - // TODO: fix this lacking code - throw UnimplementedError(); - //TODO: check network/node - case Coin.tezos: - try { - testPassed = await TezosRpcAPI.testNetworkConnection( - nodeInfo: (host: node!.host, port: node!.port), - ); - } catch (_) {} - break; - case Coin.stellar: - case Coin.stellarTestnet: - try { - testPassed = await testStellarNodeConnection(node!.host, node.port); - } catch (_) { - testPassed = false; - } - break; - - case Coin.solana: - try { - RpcClient rpcClient; - if (node!.host.startsWith("http") || node.host.startsWith("https")) { - rpcClient = RpcClient("${node.host}:${node.port}"); - } else { - rpcClient = RpcClient("http://${node.host}:${node.port}"); - } - await rpcClient.getEpochInfo().then((value) => testPassed = true); - } catch (_) { - testPassed = false; - } - break; - } - - if (testPassed) { - unawaited( - showFloatingFlushBar( - type: FlushBarType.success, - message: "Server ping success", - context: context, - ), - ); - } else { - unawaited( - showFloatingFlushBar( - type: FlushBarType.warning, - message: "Server unreachable", - context: context, - ), - ); - } - } - @override Widget build(BuildContext context) { final isDesktop = Util.isDesktop; - final node = ref.watch(nodeServiceChangeNotifierProvider - .select((value) => value.getNodeById(id: nodeId))); + final node = ref.watch( + nodeServiceChangeNotifierProvider + .select((value) => value.getNodeById(id: nodeId)), + ); - final nodesForCoin = ref.watch(nodeServiceChangeNotifierProvider - .select((value) => value.getNodesFor(coin))); + final nodesForCoin = ref.watch( + nodeServiceChangeNotifierProvider + .select((value) => value.getNodesFor(coin)), + ); final canDelete = nodesForCoin.length > 1; @@ -256,7 +97,7 @@ class _NodeDetailsViewState extends ConsumerState<NodeDetailsView> { FocusScope.of(context).unfocus(); await Future<void>.delayed(const Duration(milliseconds: 75)); } - if (mounted) { + if (context.mounted) { Navigator.of(context).pop(); } }, @@ -350,7 +191,7 @@ class _NodeDetailsViewState extends ConsumerState<NodeDetailsView> { Text( "Node details", style: STextStyles.desktopH3(context), - ) + ), ], ), Padding( @@ -420,7 +261,52 @@ class _NodeDetailsViewState extends ConsumerState<NodeDetailsView> { label: "Test connection", buttonHeight: isDesktop ? ButtonHeight.l : null, onPressed: () async { - await _testConnection(ref, context); + final node = ref + .read(nodeServiceChangeNotifierProvider) + .getNodeById(id: nodeId)!; + + final nodeFormData = NodeFormData() + ..useSSL = node.useSSL + ..trusted = node.trusted + ..name = node.name + ..host = node.host + ..login = node.loginName + ..port = node.port + ..isFailover = node.isFailover; + nodeFormData.password = await node.getPassword( + ref.read(secureStoreProvider), + ); + + if (context.mounted) { + final testPassed = await testNodeConnection( + context: context, + nodeFormData: nodeFormData, + cryptoCurrency: coin, + ref: ref, + ); + + if (testPassed) { + if (context.mounted) { + unawaited( + showFloatingFlushBar( + type: FlushBarType.success, + message: "Server ping success", + context: context, + ), + ); + } + } else { + if (context.mounted) { + unawaited( + showFloatingFlushBar( + type: FlushBarType.warning, + message: "Server unreachable", + context: context, + ), + ); + } + } + } }, ), ), 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 f6491cf1d..6ece250f1 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 @@ -33,9 +33,8 @@ import 'package:stackwallet/services/trade_notes_service.dart'; import 'package:stackwallet/services/trade_sent_from_stack_service.dart'; import 'package:stackwallet/services/trade_service.dart'; import 'package:stackwallet/services/wallets.dart'; -import 'package:stackwallet/utilities/default_nodes.dart'; +import 'package:stackwallet/supported_coins.dart'; import 'package:stackwallet/utilities/enums/backup_frequency_type.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/stack_restoring_status.dart'; import 'package:stackwallet/utilities/enums/sync_type_enum.dart'; import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'; @@ -43,6 +42,8 @@ import 'package:stackwallet/utilities/format.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/prefs.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; +import 'package:stackwallet/wallets/crypto_currency/intermediate/frost_currency.dart'; import 'package:stackwallet/wallets/isar/models/frost_wallet_info.dart'; import 'package:stackwallet/wallets/isar/models/wallet_info.dart'; import 'package:stackwallet/wallets/wallet/impl/bitcoin_frost_wallet.dart'; @@ -80,7 +81,9 @@ String getErrorMessageFromSWBException(Exception e) { String createAutoBackupFilename(String dirPath, DateTime date) { // this filename structure is important. DO NOT CHANGE - return "$dirPath/stackautobackup_${date.year}_${date.month}_${date.day}_${date.hour}_${date.minute}_${date.second}.swb"; + return "$dirPath/stackautobackup_" + "${date.year}_${date.month}_${date.day}_${date.hour}" + "_${date.minute}_${date.second}.swb"; } abstract class SWB { @@ -95,8 +98,9 @@ abstract class SWB { .log("SWB cancel restore requested", level: LogLevel.Info); } else { Logging.instance.log( - "SWB cancel restore requested while a cancellation request is currently in progress", - level: LogLevel.Warning); + "SWB cancel restore requested while a cancellation request is currently in progress", + level: LogLevel.Warning, + ); } // return completer that will complete on SWBRestoreCancelEventType.completed event @@ -129,11 +133,11 @@ abstract class SWB { String plaintext, ) async { try { - File backupFile = File(fileToSave); + final File backupFile = File(fileToSave); if (!backupFile.existsSync()) { - String jsonBackup = plaintext; - Uint8List content = Uint8List.fromList(utf8.encode(jsonBackup)); - Uint8List encryptedContent = + final String jsonBackup = plaintext; + final Uint8List content = Uint8List.fromList(utf8.encode(jsonBackup)); + final Uint8List encryptedContent = await encryptWithPassphrase(passphrase, content); backupFile .writeAsStringSync(Format.uint8listToString(encryptedContent)); @@ -153,13 +157,15 @@ abstract class SWB { int adkVersion, ) async { try { - File backupFile = File(fileToSave); + final File backupFile = File(fileToSave); if (!backupFile.existsSync()) { - String jsonBackup = plaintext; - Uint8List content = Uint8List.fromList(utf8.encode(jsonBackup)); - Uint8List encryptedContent = await encryptWithAdk( - Format.stringToUint8List(adk), content, - version: adkVersion); + final String jsonBackup = plaintext; + final Uint8List content = Uint8List.fromList(utf8.encode(jsonBackup)); + final Uint8List encryptedContent = await encryptWithAdk( + Format.stringToUint8List(adk), + content, + version: adkVersion, + ); backupFile .writeAsStringSync(Format.uint8listToString(encryptedContent)); } @@ -175,10 +181,10 @@ abstract class SWB { Tuple2<String, String> data, ) async { try { - String fileToRestore = data.item1; - String passphrase = data.item2; - File backupFile = File(fileToRestore); - String encryptedText = await backupFile.readAsString(); + final String fileToRestore = data.item1; + final String passphrase = data.item2; + final File backupFile = File(fileToRestore); + final String encryptedText = await backupFile.readAsString(); return await decryptStackWalletStringWithPassphrase( Tuple2(encryptedText, passphrase), ); @@ -192,15 +198,15 @@ abstract class SWB { Tuple2<String, String> data, ) async { try { - String encryptedText = data.item1; - String passphrase = data.item2; + final encryptedText = data.item1; + final passphrase = data.item2; - final Uint8List encryptedBytes = Format.stringToUint8List(encryptedText); + final encryptedBytes = Format.stringToUint8List(encryptedText); - Uint8List decryptedContent = + final decryptedContent = await decryptWithPassphrase(passphrase, encryptedBytes); - final String jsonBackup = utf8.decode(decryptedContent); + final jsonBackup = utf8.decode(decryptedContent); return jsonBackup; } catch (e, s) { Logging.instance.log("$e\n$s", level: LogLevel.Error); @@ -215,24 +221,27 @@ abstract class SWB { Logging.instance .log("Starting createStackWalletJSON...", level: LogLevel.Info); final _wallets = Wallets.sharedInstance; - Map<String, dynamic> backupJson = {}; - NodeService nodeService = + final Map<String, dynamic> backupJson = {}; + final NodeService nodeService = NodeService(secureStorageInterface: secureStorage); final _secureStore = secureStorage; - Logging.instance.log("createStackWalletJSON awaiting DB.instance.mutex...", - level: LogLevel.Info); + Logging.instance.log( + "createStackWalletJSON awaiting DB.instance.mutex...", + level: LogLevel.Info, + ); // prevent modification of data await DB.instance.mutex.protect(() async { Logging.instance.log( - "...createStackWalletJSON DB.instance.mutex acquired", - level: LogLevel.Info); + "...createStackWalletJSON DB.instance.mutex acquired", + level: LogLevel.Info, + ); Logging.instance.log( "SWB backing up nodes", level: LogLevel.Warning, ); try { - var primaryNodes = nodeService.primaryNodes.map((e) async { + final primaryNodes = nodeService.primaryNodes.map((e) async { final map = e.toMap(); map["password"] = await e.getPassword(_secureStore); return map; @@ -258,7 +267,7 @@ abstract class SWB { level: LogLevel.Warning, ); - Map<String, dynamic> prefs = {}; + final Map<String, dynamic> prefs = {}; final _prefs = Prefs.instance; await _prefs.init(); prefs['currency'] = _prefs.currency; @@ -282,8 +291,8 @@ abstract class SWB { level: LogLevel.Warning, ); - AddressBookService addressBookService = AddressBookService(); - var addresses = addressBookService.contacts; + final AddressBookService addressBookService = AddressBookService(); + final addresses = addressBookService.contacts; backupJson['addressBookEntries'] = addresses.map((e) => e.toMap()).toList(); @@ -292,9 +301,9 @@ abstract class SWB { level: LogLevel.Warning, ); - List<dynamic> backupWallets = []; - for (var wallet in _wallets.wallets) { - Map<String, dynamic> backupWallet = {}; + final List<dynamic> backupWallets = []; + for (final wallet in _wallets.wallets) { + final Map<String, dynamic> backupWallet = {}; backupWallet['name'] = wallet.info.name; backupWallet['id'] = wallet.walletId; backupWallet['isFavorite'] = wallet.info.isFavourite; @@ -307,10 +316,11 @@ abstract class SWB { } else if (wallet is PrivateKeyInterface) { backupWallet['privateKey'] = await wallet.getPrivateKey(); } else if (wallet is BitcoinFrostWallet) { - String? keys = await wallet.getSerializedKeys(); - String? config = await wallet.getMultisigConfig(); + final String? keys = await wallet.getSerializedKeys(); + final String? config = await wallet.getMultisigConfig(); if (keys == null || config == null) { - String err = "${wallet.info.coin.name} wallet ${wallet.info.name} " + final String err = + "${wallet.info.coin.identifier} wallet ${wallet.info.name} " "has null keys or config"; Logging.instance.log(err, level: LogLevel.Fatal); throw Exception(err); @@ -320,12 +330,12 @@ abstract class SWB { // TODO [prio=low]: solve case in which either keys or config is null. // Format keys & config as a JSON string and set otherDataJsonString. - Map<String, dynamic> frostData = {}; + final Map<String, dynamic> frostData = {}; frostData["keys"] = keys; frostData["config"] = config; backupWallet['frostWalletData'] = jsonEncode(frostData); } - backupWallet['coinName'] = wallet.info.coin.name; + backupWallet['coinName'] = wallet.info.coin.identifier; backupWallet['storedChainHeight'] = wallet.info.cachedChainHeight; // backupWallet['txidList'] = DB.instance.get<dynamic>( @@ -377,8 +387,10 @@ abstract class SWB { final tradeNotes = tradeNotesService.all; backupJson["tradeNotes"] = tradeNotes; }); - Logging.instance.log("createStackWalletJSON DB.instance.mutex released", - level: LogLevel.Info); + Logging.instance.log( + "createStackWalletJSON DB.instance.mutex released", + level: LogLevel.Info, + ); // // back up notifications data // final notificationsService = NotificationsService(); @@ -411,9 +423,10 @@ abstract class SWB { } } else { if (walletbackup['mnemonic'] is List) { - List<String> mnemonicList = (walletbackup['mnemonic'] as List<dynamic>) - .map<String>((e) => e as String) - .toList(); + final List<String> mnemonicList = + (walletbackup['mnemonic'] as List<dynamic>) + .map<String>((e) => e as String) + .toList(); mnemonic = mnemonicList.join(" ").trim(); } else { mnemonic = walletbackup['mnemonic'] as String; @@ -432,7 +445,7 @@ abstract class SWB { try { String? serializedKeys; String? multisigConfig; - if (info.coin.isFrost) { + if (info.coin is FrostCurrency) { // Decode info.otherDataJsonString for Frost recovery info. final frostData = jsonDecode(walletbackup["frostWalletData"] as String); serializedKeys = frostData["keys"] as String; @@ -544,8 +557,9 @@ abstract class SWB { await restoringFuture; Logging.instance.log( - "SWB restored: ${info.walletId} ${info.name} ${info.coin.prettyName}", - level: LogLevel.Info); + "SWB restored: ${info.walletId} ${info.name} ${info.coin.prettyName}", + level: LogLevel.Info, + ); final currentAddress = await wallet.getCurrentReceivingAddress(); uiState?.update( @@ -576,15 +590,16 @@ abstract class SWB { Map<String, String> oldToNewWalletIdMap, SecureStorageInterface secureStorageInterface, ) async { - Map<String, dynamic> prefs = validJSON["prefs"] as Map<String, dynamic>; - List<dynamic>? addressBookEntries = + final Map<String, dynamic> prefs = + validJSON["prefs"] as Map<String, dynamic>; + final List<dynamic>? addressBookEntries = validJSON["addressBookEntries"] as List?; - List<dynamic>? primaryNodes = validJSON["primaryNodes"] as List?; - List<dynamic>? nodes = validJSON["nodes"] as List?; - List<dynamic>? trades = validJSON["tradeHistory"] as List?; - List<dynamic>? tradeTxidLookupData = + final List<dynamic>? primaryNodes = validJSON["primaryNodes"] as List?; + final List<dynamic>? nodes = validJSON["nodes"] as List?; + final List<dynamic>? trades = validJSON["tradeHistory"] as List?; + final List<dynamic>? tradeTxidLookupData = validJSON["tradeTxidLookupData"] as List?; - Map<String, dynamic>? tradeNotes = + final Map<String, dynamic>? tradeNotes = validJSON["tradeNotes"] as Map<String, dynamic>?; uiState?.preferences = StackRestoringStatus.restoring; @@ -689,7 +704,7 @@ abstract class SWB { level: LogLevel.Warning, ); - List<String> _currentWalletIds = await MainDB.instance.isar.walletInfo + final List<String> _currentWalletIds = await MainDB.instance.isar.walletInfo .where() .walletIdProperty() .findAll(); @@ -697,12 +712,12 @@ abstract class SWB { final preRestoreState = PreRestoreState(_currentWalletIds.toSet(), preRestoreJSON); - Map<String, String> oldToNewWalletIdMap = {}; + final Map<String, String> oldToNewWalletIdMap = {}; - Map<String, dynamic> validJSON = + final Map<String, dynamic> validJSON = json.decode(jsonBackup) as Map<String, dynamic>; - List<dynamic> wallets = validJSON["wallets"] as List; + final List<dynamic> wallets = validJSON["wallets"] as List; // check for duplicate walletIds and assign new ones if required for (final wallet in wallets) { @@ -748,9 +763,9 @@ abstract class SWB { final List<Tuple2<dynamic, WalletInfo>> managers = []; - Map<String, WalletRestoreState> walletStates = {}; + final Map<String, WalletRestoreState> walletStates = {}; - for (var walletbackup in wallets) { + for (final walletbackup in wallets) { // check if cancel was requested and restore previous state if (_checkShouldCancel( preRestoreState, @@ -759,8 +774,10 @@ abstract class SWB { return false; } - final coin = Coin.values - .firstWhere((element) => element.name == walletbackup['coinName']); + final coin = SupportedCoins.getCryptoCurrencyFor( + walletbackup['coinName'] as String, + ); + final walletName = walletbackup['name'] as String; final walletId = oldToNewWalletIdMap[walletbackup["id"] as String]!; @@ -781,7 +798,7 @@ abstract class SWB { ); } - if (coin == Coin.firo) { + if (coin is Firo) { otherData ??= {}; // swb will do a restore so this flag should be set to false so another // rescan/restore isn't done when opening the wallet @@ -789,7 +806,7 @@ abstract class SWB { } final info = WalletInfo( - coinName: coin.name, + coinName: coin.identifier, walletId: walletId, name: walletName, mainAddressType: coin.primaryAddressType, @@ -798,10 +815,10 @@ abstract class SWB { cachedChainHeight: walletbackup['storedChainHeight'] as int? ?? 0, ); - var node = nodeService.getPrimaryNodeFor(coin: coin); + var node = nodeService.getPrimaryNodeFor(currency: coin); if (node == null) { - node = DefaultNodes.getNodeFor(coin); + node = coin.defaultNode; await nodeService.setPrimaryNodeFor(coin: coin, node: node); } @@ -845,7 +862,7 @@ abstract class SWB { // set the states so the ui can display each status as they update during restores uiState?.walletStates = walletStates; - List<Future<bool>> restoreStatuses = []; + final List<Future<bool>> restoreStatuses = []; // start restoring wallets for (final tuple in managers) { // check if cancel was requested and restore previous state @@ -873,7 +890,7 @@ abstract class SWB { return false; } - for (Future<bool> status in restoreStatuses) { + for (final Future<bool> status in restoreStatuses) { // check if cancel was requested and restore previous state if (_checkShouldCancel( preRestoreState, @@ -905,17 +922,18 @@ abstract class SWB { PreRestoreState revertToState, SecureStorageInterface secureStorageInterface, ) async { - Map<String, dynamic> prefs = + final Map<String, dynamic> prefs = revertToState.validJSON["prefs"] as Map<String, dynamic>; - List<dynamic>? addressBookEntries = + final List<dynamic>? addressBookEntries = revertToState.validJSON["addressBookEntries"] as List?; - List<dynamic>? primaryNodes = + final List<dynamic>? primaryNodes = revertToState.validJSON["primaryNodes"] as List?; - List<dynamic>? nodes = revertToState.validJSON["nodes"] as List?; - List<dynamic>? trades = revertToState.validJSON["tradeHistory"] as List?; - List<dynamic>? tradeTxidLookupData = + final List<dynamic>? nodes = revertToState.validJSON["nodes"] as List?; + final List<dynamic>? trades = + revertToState.validJSON["tradeHistory"] as List?; + final List<dynamic>? tradeTxidLookupData = revertToState.validJSON["tradeTxidLookupData"] as List?; - Map<String, dynamic>? tradeNotes = + final Map<String, dynamic>? tradeNotes = revertToState.validJSON["tradeNotes"] as Map<String, dynamic>?; // prefs @@ -971,7 +989,7 @@ abstract class SWB { } // nodes - NodeService nodeService = NodeService( + final NodeService nodeService = NodeService( secureStorageInterface: secureStorageInterface, ); final currentNodes = nodeService.nodes; @@ -1015,10 +1033,12 @@ abstract class SWB { // primary nodes if (primaryNodes != null) { - for (var node in primaryNodes) { + for (final node in primaryNodes) { try { await nodeService.setPrimaryNodeFor( - coin: coinFromPrettyName(node['coinName'] as String), + coin: SupportedCoins.getCryptoCurrencyByPrettyName( + node['coinName'] as String, + ), node: nodeService.getNodeById(id: node['id'] as String)!, ); } catch (e, s) { @@ -1050,12 +1070,15 @@ abstract class SWB { // trade existed before attempted restore so we don't delete it, only // revert data to pre restore state await tradesService.edit( - trade: Trade.fromMap(tradeData as Map<String, dynamic>), - shouldNotifyListeners: true); + trade: Trade.fromMap(tradeData as Map<String, dynamic>), + shouldNotifyListeners: true, + ); } else { // trade did not exist before so we delete it await tradesService.delete( - trade: tradeTx, shouldNotifyListeners: true); + trade: tradeTx, + shouldNotifyListeners: true, + ); } } } @@ -1093,7 +1116,7 @@ abstract class SWB { if (tradeTxidLookupData != null) { for (int i = 0; i < tradeTxidLookupData.length; i++) { final json = Map<String, dynamic>.from(tradeTxidLookupData[i] as Map); - TradeWalletLookup lookup = TradeWalletLookup.fromJson(json); + final TradeWalletLookup lookup = TradeWalletLookup.fromJson(json); await tradeTxidLookupDataService.save(tradeWalletLookup: lookup); } } @@ -1137,8 +1160,9 @@ abstract class SWB { _prefs.isAutoBackupEnabled = prefs['isAutoBackupEnabled'] as bool; _prefs.autoBackupLocation = prefs['autoBackupLocation'] as String?; _prefs.backupFrequencyType = BackupFrequencyType.values.firstWhere( - (e) => e.name == (prefs['backupFrequencyType'] as String?), - orElse: () => BackupFrequencyType.everyAppStart); + (e) => e.name == (prefs['backupFrequencyType'] as String?), + orElse: () => BackupFrequencyType.everyAppStart, + ); _prefs.lastAutoBackup = DateTime.tryParse(prefs['lastAutoBackup'] as String? ?? ""); } @@ -1146,10 +1170,10 @@ abstract class SWB { static Future<void> _restoreAddressBook( List<dynamic> addressBookEntries, ) async { - AddressBookService addressBookService = AddressBookService(); - for (var contact in addressBookEntries) { - List<ContactAddressEntry> addresses = []; - for (var address in (contact['addresses'] as List<dynamic>)) { + final AddressBookService addressBookService = AddressBookService(); + for (final contact in addressBookEntries) { + final List<ContactAddressEntry> addresses = []; + for (final address in (contact['addresses'] as List<dynamic>)) { addresses.add( ContactAddressEntry() ..coinName = address['coin'] as String @@ -1175,11 +1199,11 @@ abstract class SWB { List<dynamic>? primaryNodes, SecureStorageInterface secureStorageInterface, ) async { - NodeService nodeService = NodeService( + final NodeService nodeService = NodeService( secureStorageInterface: secureStorageInterface, ); if (nodes != null) { - for (var node in nodes) { + for (final node in nodes) { await nodeService.add( NodeModel( host: node['host'] as String, @@ -1199,10 +1223,12 @@ abstract class SWB { } } if (primaryNodes != null) { - for (var node in primaryNodes) { + for (final node in primaryNodes) { try { await nodeService.setPrimaryNodeFor( - coin: coinFromPrettyName(node['coinName'] as String), + coin: SupportedCoins.getCryptoCurrencyByPrettyName( + node['coinName'] as String, + ), node: nodeService.getNodeById(id: node['id'] as String)!, ); } catch (e, s) { @@ -1272,16 +1298,18 @@ abstract class SWB { final json = Map<String, dynamic>.from(tradeTxidLookupData[i] as Map); TradeWalletLookup lookup = TradeWalletLookup.fromJson(json); // update walletIds - List<String> walletIds = + final List<String> walletIds = lookup.walletIds.map((e) => oldToNewWalletIdMap[e]!).toList(); lookup = lookup.copyWith(walletIds: walletIds); final oldLookup = DB.instance.get<TradeWalletLookup>( - boxName: DB.boxNameTradeLookup, key: lookup.uuid); + boxName: DB.boxNameTradeLookup, + key: lookup.uuid, + ); if (oldLookup != null) { if (oldLookup.txid == lookup.txid && oldLookup.tradeId == lookup.tradeId) { - List<String> mergedList = oldLookup.walletIds; + final List<String> mergedList = oldLookup.walletIds; for (final id in lookup.walletIds) { if (!mergedList.contains(id)) { mergedList.add(id); @@ -1308,7 +1336,9 @@ abstract class SWB { final tradeNotesService = TradeNotesService(); for (final note in tradeNotes.entries) { await tradeNotesService.set( - tradeId: note.key, note: note.value as String); + tradeId: note.key, + note: note.value as String, + ); } } } diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/sub_widgets/restoring_wallet_card.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/sub_widgets/restoring_wallet_card.dart index 36c3d7c81..53ad106b5 100644 --- a/lib/pages/settings_views/global_settings_view/stack_backup_views/sub_widgets/restoring_wallet_card.dart +++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/sub_widgets/restoring_wallet_card.dart @@ -20,8 +20,8 @@ import 'package:stackwallet/providers/stack_restore/stack_restoring_ui_state_pro import 'package:stackwallet/route_generator.dart'; import 'package:stackwallet/themes/coin_icon_provider.dart'; import 'package:stackwallet/themes/stack_colors.dart'; +import 'package:stackwallet/themes/theme_providers.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/stack_restoring_status.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; @@ -89,9 +89,7 @@ class _RestoringWalletCardState extends ConsumerState<RestoringWalletCard> { height: 32, child: RoundedContainer( padding: const EdgeInsets.all(0), - color: Theme.of(context) - .extension<StackColors>()! - .colorForCoin(coin), + color: ref.watch(pCoinColor(coin)), child: Center( child: SvgPicture.file( File( @@ -212,9 +210,7 @@ class _RestoringWalletCardState extends ConsumerState<RestoringWalletCard> { height: 32, child: RoundedContainer( padding: const EdgeInsets.all(0), - color: Theme.of(context) - .extension<StackColors>()! - .colorForCoin(coin), + color: ref.watch(pCoinColor(coin)), child: Center( child: SvgPicture.file( File( @@ -239,7 +235,7 @@ class _RestoringWalletCardState extends ConsumerState<RestoringWalletCard> { try { // final mnemonicList = await manager.mnemonic; // int maxUnusedAddressGap = 20; - // if (coin == Coin.firo) { + // if (coin is Firo) { // maxUnusedAddressGap = 50; // } // const maxNumberOfIndexesToCheck = 1000; diff --git a/lib/pages/settings_views/global_settings_view/startup_preferences/startup_wallet_selection_view.dart b/lib/pages/settings_views/global_settings_view/startup_preferences/startup_wallet_selection_view.dart index 6e057eaf4..d636a8d5a 100644 --- a/lib/pages/settings_views/global_settings_view/startup_preferences/startup_wallet_selection_view.dart +++ b/lib/pages/settings_views/global_settings_view/startup_preferences/startup_wallet_selection_view.dart @@ -16,6 +16,7 @@ import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/themes/coin_icon_provider.dart'; import 'package:stackwallet/themes/stack_colors.dart'; +import 'package:stackwallet/themes/theme_providers.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; @@ -63,165 +64,181 @@ class _StartupWalletSelectionViewState ), ), ), - body: LayoutBuilder(builder: (context, constraints) { - return Padding( - padding: const EdgeInsets.only( - left: 12, - top: 12, - right: 12, - ), - child: SingleChildScrollView( - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: constraints.maxHeight - 24, - ), - child: IntrinsicHeight( - child: Padding( - padding: const EdgeInsets.all(4), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox( - height: 4, - ), - Text( - "Select a wallet to load into immediately on startup", - style: STextStyles.smallMed12(context), - ), - const SizedBox( - height: 12, - ), - RoundedWhiteContainer( - padding: const EdgeInsets.all(0), - child: Column( - children: [ - ...wallets.map( - (wallet) => Padding( - padding: const EdgeInsets.all(12), - child: Row( - key: Key( - "startupWalletSelectionGroupKey_${wallet.walletId}"), - children: [ - Container( - decoration: BoxDecoration( - color: Theme.of(context) - .extension<StackColors>()! - .colorForCoin( - ref.watch(pWalletCoin( - wallet.walletId)), - ) - .withOpacity(0.5), - borderRadius: BorderRadius.circular( - Constants.size.circularBorderRadius, + body: LayoutBuilder( + builder: (context, constraints) { + return Padding( + padding: const EdgeInsets.only( + left: 12, + top: 12, + right: 12, + ), + child: SingleChildScrollView( + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: constraints.maxHeight - 24, + ), + child: IntrinsicHeight( + child: Padding( + padding: const EdgeInsets.all(4), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox( + height: 4, + ), + Text( + "Select a wallet to load into immediately on startup", + style: STextStyles.smallMed12(context), + ), + const SizedBox( + height: 12, + ), + RoundedWhiteContainer( + padding: const EdgeInsets.all(0), + child: Column( + children: [ + ...wallets.map( + (wallet) => Padding( + padding: const EdgeInsets.all(12), + child: Row( + key: Key( + "startupWalletSelectionGroupKey_${wallet.walletId}", + ), + children: [ + Container( + decoration: BoxDecoration( + color: ref + .watch( + pCoinColor( + ref.watch( + pWalletCoin( + wallet.walletId, + ), + ), + ), + ) + .withOpacity(0.5), + borderRadius: BorderRadius.circular( + Constants + .size.circularBorderRadius, + ), ), - ), - child: Padding( - padding: const EdgeInsets.all(4), - child: SvgPicture.file( - File( - ref.watch( - coinIconProvider( - ref.watch(pWalletCoin( - wallet.walletId)), + child: Padding( + padding: const EdgeInsets.all(4), + child: SvgPicture.file( + File( + ref.watch( + coinIconProvider( + ref.watch( + pWalletCoin( + wallet.walletId, + ), + ), + ), ), ), + width: 20, + height: 20, ), - width: 20, - height: 20, ), ), - ), - const SizedBox( - width: 12, - ), - Expanded( - child: Column( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Text( - ref.watch( - pWalletName(wallet.walletId)), - style: STextStyles.titleBold12( - context), - ), - // const SizedBox( - // height: 2, - // ), - // FutureBuilder( - // future: manager.totalBalance, - // builder: (builderContext, - // AsyncSnapshot<Decimal> snapshot) { - // if (snapshot.connectionState == - // ConnectionState.done && - // snapshot.hasData) { - // return Text( - // "${Format.localizedStringAsFixed( - // value: snapshot.data!, - // locale: ref.watch( - // localeServiceChangeNotifierProvider - // .select((value) => - // value.locale)), - // decimalPlaces: 8, - // )} ${manager.coin.ticker}", - // style: STextStyles.itemSubtitle(context), - // ); - // } else { - // return AnimatedText( - // stringsToLoopThrough: const [ - // "Loading balance", - // "Loading balance.", - // "Loading balance..", - // "Loading balance..." - // ], - // style: STextStyles.itemSubtitle(context), - // ); - // } - // }, - // ), - ], + const SizedBox( + width: 12, ), - ), - SizedBox( - height: 20, - width: 20, - child: Radio( - activeColor: Theme.of(context) - .extension<StackColors>()! - .radioButtonIconEnabled, - value: wallet.walletId, - groupValue: ref.watch( - prefsChangeNotifierProvider.select( + Expanded( + child: Column( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + ref.watch( + pWalletName(wallet.walletId), + ), + style: STextStyles.titleBold12( + context, + ), + ), + // const SizedBox( + // height: 2, + // ), + // FutureBuilder( + // future: manager.totalBalance, + // builder: (builderContext, + // AsyncSnapshot<Decimal> snapshot) { + // if (snapshot.connectionState == + // ConnectionState.done && + // snapshot.hasData) { + // return Text( + // "${Format.localizedStringAsFixed( + // value: snapshot.data!, + // locale: ref.watch( + // localeServiceChangeNotifierProvider + // .select((value) => + // value.locale)), + // decimalPlaces: 8, + // )} ${manager.coin.ticker}", + // style: STextStyles.itemSubtitle(context), + // ); + // } else { + // return AnimatedText( + // stringsToLoopThrough: const [ + // "Loading balance", + // "Loading balance.", + // "Loading balance..", + // "Loading balance..." + // ], + // style: STextStyles.itemSubtitle(context), + // ); + // } + // }, + // ), + ], + ), + ), + SizedBox( + height: 20, + width: 20, + child: Radio( + activeColor: Theme.of(context) + .extension<StackColors>()! + .radioButtonIconEnabled, + value: wallet.walletId, + groupValue: ref.watch( + prefsChangeNotifierProvider + .select( (value) => - value.startupWalletId), + value.startupWalletId, + ), + ), + onChanged: (value) { + if (value is String) { + ref + .read( + prefsChangeNotifierProvider, + ) + .startupWalletId = value; + } + }, ), - onChanged: (value) { - if (value is String) { - ref - .read( - prefsChangeNotifierProvider) - .startupWalletId = value; - } - }, ), - ), - ], + ], + ), ), ), - ), - ], + ], + ), ), - ), - ], + ], + ), ), ), ), ), - ), - ); - }), + ); + }, + ), ), ); } diff --git a/lib/pages/settings_views/global_settings_view/syncing_preferences_views/wallet_syncing_options_view.dart b/lib/pages/settings_views/global_settings_view/syncing_preferences_views/wallet_syncing_options_view.dart index 8ded05dd6..375534e4a 100644 --- a/lib/pages/settings_views/global_settings_view/syncing_preferences_views/wallet_syncing_options_view.dart +++ b/lib/pages/settings_views/global_settings_view/syncing_preferences_views/wallet_syncing_options_view.dart @@ -16,6 +16,7 @@ import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/themes/coin_icon_provider.dart'; import 'package:stackwallet/themes/stack_colors.dart'; +import 'package:stackwallet/themes/theme_providers.dart'; import 'package:stackwallet/utilities/amount/amount_formatter.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/text_styles.dart'; @@ -117,9 +118,8 @@ class WalletSyncingOptionsView extends ConsumerWidget { children: [ Container( decoration: BoxDecoration( - color: Theme.of(context) - .extension<StackColors>()! - .colorForCoin(info.coin) + color: ref + .watch(pCoinColor(info.coin)) .withOpacity(0.5), borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, diff --git a/lib/pages/settings_views/sub_widgets/nodes_list.dart b/lib/pages/settings_views/sub_widgets/nodes_list.dart index 52d9b8861..de01c392c 100644 --- a/lib/pages/settings_views/sub_widgets/nodes_list.dart +++ b/lib/pages/settings_views/sub_widgets/nodes_list.dart @@ -11,39 +11,39 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/providers/global/node_service_provider.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/node_card.dart'; class NodesList extends ConsumerWidget { const NodesList({ - Key? key, + super.key, required this.coin, required this.popBackToRoute, - }) : super(key: key); + }); - final Coin coin; + final CryptoCurrency coin; final String popBackToRoute; @override Widget build(BuildContext context, WidgetRef ref) { - final nodes = ref.watch(nodeServiceChangeNotifierProvider - .select((value) => value.getNodesFor(coin))); + final nodes = ref.watch( + nodeServiceChangeNotifierProvider + .select((value) => value.getNodesFor(coin)), + ); return Column( children: [ - ...nodes - .map( - (node) => Padding( - padding: const EdgeInsets.symmetric(vertical: 4), - child: NodeCard( - key: Key("${node.id}_card_key"), - nodeId: node.id, - coin: coin, - popBackToRoute: popBackToRoute, - ), - ), - ) - .toList(), + ...nodes.map( + (node) => Padding( + padding: const EdgeInsets.symmetric(vertical: 4), + child: NodeCard( + key: Key("${node.id}_card_key"), + nodeId: node.id, + coin: coin, + popBackToRoute: popBackToRoute, + ), + ), + ), ], ); } diff --git a/lib/pages/settings_views/wallet_settings_view/wallet_network_settings_view/wallet_network_settings_view.dart b/lib/pages/settings_views/wallet_settings_view/wallet_network_settings_view/wallet_network_settings_view.dart index 6fbf8df93..9eae180f9 100644 --- a/lib/pages/settings_views/wallet_settings_view/wallet_network_settings_view/wallet_network_settings_view.dart +++ b/lib/pages/settings_views/wallet_settings_view/wallet_network_settings_view/wallet_network_settings_view.dart @@ -32,9 +32,11 @@ import 'package:stackwallet/services/tor_service.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/epiccash.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/monero.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/wownero.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; import 'package:stackwallet/wallets/wallet/impl/epiccash_wallet.dart'; import 'package:stackwallet/wallets/wallet/impl/monero_wallet.dart'; @@ -57,12 +59,12 @@ import 'package:wakelock/wakelock.dart'; /// [eventBus] should only be set during testing class WalletNetworkSettingsView extends ConsumerStatefulWidget { const WalletNetworkSettingsView({ - Key? key, + super.key, required this.walletId, required this.initialSyncStatus, required this.initialNodeStatus, this.eventBus, - }) : super(key: key); + }); final String walletId; final WalletSyncStatus initialSyncStatus; @@ -260,7 +262,7 @@ class _WalletNetworkSettingsViewState final coin = ref.read(pWalletCoin(widget.walletId)); - if (coin == Coin.monero || coin == Coin.wownero || coin == Coin.epicCash) { + if (coin is Monero || coin is Wownero || coin is Epiccash) { _blocksRemainingSubscription = eventBus.on<BlocksRemainingEvent>().listen( (event) async { if (event.walletId == widget.walletId) { @@ -319,22 +321,22 @@ class _WalletNetworkSettingsViewState final coin = ref.watch(pWalletCoin(widget.walletId)); - if (coin == Coin.monero) { - double highestPercent = + if (coin is Monero) { + final double highestPercent = (ref.read(pWallets).getWallet(widget.walletId) as MoneroWallet) .highestPercentCached; if (_percent < highestPercent) { _percent = highestPercent.clamp(0.0, 1.0); } - } else if (coin == Coin.wownero) { - double highestPercent = + } else if (coin is Wownero) { + final double highestPercent = (ref.watch(pWallets).getWallet(widget.walletId) as WowneroWallet) .highestPercentCached; if (_percent < highestPercent) { _percent = highestPercent.clamp(0.0, 1.0); } - } else if (coin == Coin.epicCash) { - double highestPercent = + } else if (coin is Epiccash) { + final double highestPercent = (ref.watch(pWallets).getWallet(widget.walletId) as EpiccashWallet) .highestPercent; if (_percent < highestPercent) { @@ -360,7 +362,7 @@ class _WalletNetworkSettingsViewState style: STextStyles.navBarTitle(context), ), actions: [ - if (ref.watch(pWalletCoin(widget.walletId)) != Coin.epicCash) + if (ref.watch(pWalletCoin(widget.walletId)) is! Epiccash) Padding( padding: const EdgeInsets.only( top: 10, @@ -371,7 +373,8 @@ class _WalletNetworkSettingsViewState aspectRatio: 1, child: AppBarIconButton( key: const Key( - "walletNetworkSettingsAddNewNodeViewButton"), + "walletNetworkSettingsAddNewNodeViewButton", + ), size: 36, shadows: const [], color: Theme.of(context) @@ -402,8 +405,8 @@ class _WalletNetworkSettingsViewState .extension<StackColors>()! .popupBG, borderRadius: BorderRadius.circular( - Constants - .size.circularBorderRadius), + Constants.size.circularBorderRadius, + ), // boxShadow: [CFColors.standardBoxShadow], boxShadow: const [], ), @@ -431,7 +434,8 @@ class _WalletNetworkSettingsViewState child: Text( "Rescan blockchain", style: STextStyles.baseXS( - context), + context, + ), ), ), ), @@ -620,9 +624,9 @@ class _WalletNetworkSettingsViewState .accentColorYellow, ), ), - if (coin == Coin.monero || - coin == Coin.wownero || - coin == Coin.epicCash) + if (coin is Monero || + coin is Wownero || + coin is Epiccash) Text( " (Blocks to go: ${_blocksRemaining == -1 ? "?" : _blocksRemaining})", style: STextStyles.syncPercent(context) @@ -633,7 +637,7 @@ class _WalletNetworkSettingsViewState ), ), ], - ) + ), ], ), ), @@ -768,8 +772,9 @@ class _WalletNetworkSettingsViewState : STextStyles.smallMed12(context), ), CustomTextButton( - text: ref.watch(prefsChangeNotifierProvider - .select((value) => value.useTor)) + text: ref.watch( + prefsChangeNotifierProvider.select((value) => value.useTor), + ) ? "Disconnect" : "Connect", onTap: onTorTapped, @@ -787,8 +792,9 @@ class _WalletNetworkSettingsViewState isDesktop ? const EdgeInsets.all(16) : const EdgeInsets.all(12), child: Row( children: [ - if (ref.watch(prefsChangeNotifierProvider - .select((value) => value.useTor))) + if (ref.watch( + prefsChangeNotifierProvider.select((value) => value.useTor), + )) Container( width: _iconSize, height: _iconSize, @@ -810,8 +816,9 @@ class _WalletNetworkSettingsViewState ), ), ), - if (!ref.watch(prefsChangeNotifierProvider - .select((value) => value.useTor))) + if (!ref.watch( + prefsChangeNotifierProvider.select((value) => value.useTor), + )) Container( width: _iconSize, height: _iconSize, @@ -916,13 +923,11 @@ class _WalletNetworkSettingsViewState coin: ref.watch(pWalletCoin(widget.walletId)), popBackToRoute: WalletNetworkSettingsView.routeName, ), - if (isDesktop && - ref.watch(pWalletCoin(widget.walletId)) != Coin.epicCash) + if (isDesktop && ref.watch(pWalletCoin(widget.walletId)) is! Epiccash) const SizedBox( height: 32, ), - if (isDesktop && - ref.watch(pWalletCoin(widget.walletId)) != Coin.epicCash) + if (isDesktop && ref.watch(pWalletCoin(widget.walletId)) is! Epiccash) Padding( padding: const EdgeInsets.only( bottom: 12, @@ -938,8 +943,7 @@ class _WalletNetworkSettingsViewState ], ), ), - if (isDesktop && - ref.watch(pWalletCoin(widget.walletId)) != Coin.epicCash) + if (isDesktop && ref.watch(pWalletCoin(widget.walletId)) is! Epiccash) RoundedWhiteContainer( borderColor: isDesktop ? Theme.of(context).extension<StackColors>()!.background @@ -987,8 +991,8 @@ class _WalletNetworkSettingsViewState Text( "Advanced", style: STextStyles.desktopTextExtraExtraSmall( - context) - .copyWith( + context, + ).copyWith( color: Theme.of(context) .extension<StackColors>()! .textDark, @@ -997,10 +1001,11 @@ class _WalletNetworkSettingsViewState Text( "Rescan blockchain", style: STextStyles.desktopTextExtraExtraSmall( - context), + context, + ), ), ], - ) + ), ], ), SvgPicture.asset( diff --git a/lib/pages/settings_views/wallet_settings_view/wallet_settings_view.dart b/lib/pages/settings_views/wallet_settings_view/wallet_settings_view.dart index 66dfb8c23..63130bbdd 100644 --- a/lib/pages/settings_views/wallet_settings_view/wallet_settings_view.dart +++ b/lib/pages/settings_views/wallet_settings_view/wallet_settings_view.dart @@ -36,10 +36,13 @@ import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_ import 'package:stackwallet/services/event_bus/global_event_bus.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/show_loading.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; +import 'package:stackwallet/wallets/crypto_currency/intermediate/frost_currency.dart'; +import 'package:stackwallet/wallets/crypto_currency/intermediate/nano_currency.dart'; import 'package:stackwallet/wallets/wallet/impl/bitcoin_frost_wallet.dart'; import 'package:stackwallet/wallets/wallet/impl/epiccash_wallet.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/mnemonic_interface.dart'; @@ -64,7 +67,7 @@ class WalletSettingsView extends ConsumerStatefulWidget { static const String routeName = "/walletSettings"; final String walletId; - final Coin coin; + final CryptoCurrency coin; final WalletSyncStatus initialSyncStatus; final NodeConnectionStatus initialNodeStatus; final EventBus? eventBus; @@ -75,7 +78,7 @@ class WalletSettingsView extends ConsumerStatefulWidget { class _WalletSettingsViewState extends ConsumerState<WalletSettingsView> { late final String walletId; - late final Coin coin; + late final CryptoCurrency coin; late String xpub; late final bool xPubEnabled; @@ -206,11 +209,11 @@ class _WalletSettingsViewState extends ConsumerState<WalletSettingsView> { ); }, ), - if (coin.isFrost) + if (coin is FrostCurrency) const SizedBox( height: 8, ), - if (coin.isFrost) + if (coin is FrostCurrency) SettingsListButton( iconAssetName: Assets.svg.addressBook2, iconSize: 16, @@ -376,11 +379,11 @@ class _WalletSettingsViewState extends ConsumerState<WalletSettingsView> { ); }, ), - if (coin == Coin.firo) + if (coin is Firo) const SizedBox( height: 8, ), - if (coin == Coin.firo) + if (coin is Firo) Consumer( builder: (_, ref, __) { return SettingsListButton( @@ -419,7 +422,7 @@ class _WalletSettingsViewState extends ConsumerState<WalletSettingsView> { ), DB.instance .clearSharedTransactionCache( - coin: coin, + currency: coin, ), ], ), @@ -431,11 +434,11 @@ class _WalletSettingsViewState extends ConsumerState<WalletSettingsView> { ); }, ), - if (coin == Coin.nano || coin == Coin.banano) + if (coin is NanoCurrency) const SizedBox( height: 8, ), - if (coin == Coin.nano || coin == Coin.banano) + if (coin is NanoCurrency) Consumer( builder: (_, ref, __) { return SettingsListButton( diff --git a/lib/pages/token_view/sub_widgets/my_token_select_item.dart b/lib/pages/token_view/sub_widgets/my_token_select_item.dart index 2fd42300d..af76effde 100644 --- a/lib/pages/token_view/sub_widgets/my_token_select_item.dart +++ b/lib/pages/token_view/sub_widgets/my_token_select_item.dart @@ -21,10 +21,11 @@ import 'package:stackwallet/services/ethereum/cached_eth_token_balance.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/amount/amount_formatter.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/show_loading.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/ethereum.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/isar/providers/eth/current_token_wallet_provider.dart'; import 'package:stackwallet/wallets/isar/providers/eth/token_balance_provider.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; @@ -178,7 +179,10 @@ class _MyTokenSelectItemState extends ConsumerState<MyTokenSelectItem> { ), const Spacer(), Text( - ref.watch(pAmountFormatter(Coin.ethereum)).format( + ref + .watch(pAmountFormatter( + Ethereum(CryptoCurrencyNetwork.main))) + .format( ref .watch(pTokenBalance( ( diff --git a/lib/pages/token_view/sub_widgets/token_summary.dart b/lib/pages/token_view/sub_widgets/token_summary.dart index a852d0954..f4c97b960 100644 --- a/lib/pages/token_view/sub_widgets/token_summary.dart +++ b/lib/pages/token_view/sub_widgets/token_summary.dart @@ -30,8 +30,9 @@ import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount_formatter.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/ethereum.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/isar/providers/eth/current_token_wallet_provider.dart'; import 'package:stackwallet/wallets/isar/providers/eth/token_balance_provider.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; @@ -41,10 +42,10 @@ import 'package:tuple/tuple.dart'; class TokenSummary extends ConsumerWidget { const TokenSummary({ - Key? key, + super.key, required this.walletId, required this.initialSyncStatus, - }) : super(key: key); + }); final String walletId; final WalletSyncStatus initialSyncStatus; @@ -54,7 +55,8 @@ class TokenSummary extends ConsumerWidget { final token = ref.watch(pCurrentTokenWallet.select((value) => value!.tokenContract)); final balance = ref.watch( - pTokenBalance((walletId: walletId, contractAddress: token.address))); + pTokenBalance((walletId: walletId, contractAddress: token.address)), + ); return Stack( children: [ @@ -96,7 +98,13 @@ class TokenSummary extends ConsumerWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ Text( - ref.watch(pAmountFormatter(Coin.ethereum)).format( + ref + .watch( + pAmountFormatter( + Ethereum(CryptoCurrencyNetwork.main), + ), + ) + .format( balance.total, ethContract: token, ), @@ -173,13 +181,14 @@ class TokenSummary extends ConsumerWidget { class TokenWalletOptions extends ConsumerWidget { const TokenWalletOptions({ - Key? key, + super.key, required this.walletId, required this.tokenContract, - }) : super(key: key); + }); final String walletId; final EthContract tokenContract; + CryptoCurrency get ethereum => Ethereum(CryptoCurrencyNetwork.main); void _onExchangePressed(BuildContext context) async { unawaited( @@ -187,7 +196,7 @@ class TokenWalletOptions extends ConsumerWidget { WalletInitiatedExchangeView.routeName, arguments: Tuple3( walletId, - Coin.ethereum, + ethereum, tokenContract, ), ), @@ -199,7 +208,7 @@ class TokenWalletOptions extends ConsumerWidget { Navigator.of(context).pushNamed( BuyInWalletView.routeName, arguments: Tuple2( - Coin.ethereum, + ethereum, tokenContract, ), ), @@ -233,7 +242,7 @@ class TokenWalletOptions extends ConsumerWidget { TokenSendView.routeName, arguments: Tuple3( walletId, - Coin.ethereum, + ethereum, tokenContract, ), ); @@ -268,11 +277,11 @@ class TokenWalletOptions extends ConsumerWidget { class TokenOptionsButton extends StatelessWidget { const TokenOptionsButton({ - Key? key, + super.key, required this.onPressed, required this.subLabel, required this.iconAssetPathSVG, - }) : super(key: key); + }); final VoidCallback onPressed; final String subLabel; @@ -344,7 +353,7 @@ class TokenOptionsButton extends StatelessWidget { .extension<StackColors>()! .tokenSummaryTextPrimary, ), - ) + ), ], ); } diff --git a/lib/pages/wallet_view/sub_widgets/transactions_list.dart b/lib/pages/wallet_view/sub_widgets/transactions_list.dart index d3886378e..dd89c74b1 100644 --- a/lib/pages/wallet_view/sub_widgets/transactions_list.dart +++ b/lib/pages/wallet_view/sub_widgets/transactions_list.dart @@ -23,9 +23,9 @@ import 'package:stackwallet/providers/global/wallets_provider.dart'; import 'package:stackwallet/route_generator.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; import 'package:stackwallet/widgets/desktop/desktop_dialog.dart'; import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart'; @@ -36,9 +36,9 @@ import 'package:tuple/tuple.dart'; class TransactionsList extends ConsumerStatefulWidget { const TransactionsList({ - Key? key, + super.key, required this.walletId, - }) : super(key: key); + }); final String walletId; @@ -80,7 +80,7 @@ class _TransactionsListState extends ConsumerState<TransactionsList> { BuildContext context, Transaction tx, BorderRadius? radius, - Coin coin, + CryptoCurrency coin, int chainHeight, ) { final matchingTrades = ref diff --git a/lib/pages/wallet_view/sub_widgets/tx_icon.dart b/lib/pages/wallet_view/sub_widgets/tx_icon.dart index 11920f7c2..b8bfa2c1a 100644 --- a/lib/pages/wallet_view/sub_widgets/tx_icon.dart +++ b/lib/pages/wallet_view/sub_widgets/tx_icon.dart @@ -19,19 +19,19 @@ import 'package:stackwallet/models/isar/stack_theme.dart'; import 'package:stackwallet/providers/global/wallets_provider.dart'; import 'package:stackwallet/themes/theme_providers.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; class TxIcon extends ConsumerWidget { const TxIcon({ - Key? key, + super.key, required this.transaction, required this.currentHeight, required this.coin, - }) : super(key: key); + }); final Object transaction; final int currentHeight; - final Coin coin; + final CryptoCurrency coin; static const Size size = Size(32, 32); diff --git a/lib/pages/wallet_view/sub_widgets/wallet_balance_toggle_sheet.dart b/lib/pages/wallet_view/sub_widgets/wallet_balance_toggle_sheet.dart index af0eca1c6..27d2ba4a1 100644 --- a/lib/pages/wallet_view/sub_widgets/wallet_balance_toggle_sheet.dart +++ b/lib/pages/wallet_view/sub_widgets/wallet_balance_toggle_sheet.dart @@ -17,9 +17,10 @@ import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount_formatter.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/wallet_balance_toggle_state.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; enum _BalanceType { @@ -44,7 +45,7 @@ class WalletBalanceToggleSheet extends ConsumerWidget { final maxHeight = MediaQuery.of(context).size.height * 0.90; final coin = ref.watch(pWalletCoin(walletId)); - final isFiro = coin == Coin.firo || coin == Coin.firoTestNet; + final isFiro = coin is Firo; final balance = ref.watch(pWalletBalance(walletId)); @@ -305,7 +306,7 @@ class BalanceSelector<T> extends ConsumerWidget { }); final String title; - final Coin coin; + final CryptoCurrency coin; final Amount balance; final VoidCallback onPressed; final void Function(T?) onChanged; diff --git a/lib/pages/wallet_view/sub_widgets/wallet_summary_info.dart b/lib/pages/wallet_view/sub_widgets/wallet_summary_info.dart index fa01d1ac6..9a6999ae4 100644 --- a/lib/pages/wallet_view/sub_widgets/wallet_summary_info.dart +++ b/lib/pages/wallet_view/sub_widgets/wallet_summary_info.dart @@ -26,19 +26,20 @@ import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount_formatter.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/wallet_balance_toggle_state.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/banano.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; import 'package:stackwallet/wallets/wallet/impl/banano_wallet.dart'; import 'package:stackwallet/widgets/conditional_parent.dart'; class WalletSummaryInfo extends ConsumerWidget { const WalletSummaryInfo({ - Key? key, + super.key, required this.walletId, required this.initialSyncStatus, - }) : super(key: key); + }); final String walletId; final WalletSyncStatus initialSyncStatus; @@ -86,7 +87,7 @@ class WalletSummaryInfo extends ConsumerWidget { final Amount balanceToShow; final String title; - if (coin == Coin.firo || coin == Coin.firoTestNet) { + if (coin is Firo) { final type = ref.watch(publicPrivateBalanceStateProvider.state).state; title = "${_showAvailable ? "Available" : "Full"} ${type.name.capitalize()} balance"; @@ -113,7 +114,7 @@ class WalletSummaryInfo extends ConsumerWidget { List<int>? imageBytes; - if (coin == Coin.banano) { + if (coin is Banano) { imageBytes = (ref.watch(pWallets).getWallet(walletId) as BananoWallet) .getMonkeyImageBytes(); } diff --git a/lib/pages/wallet_view/transaction_views/all_transactions_view.dart b/lib/pages/wallet_view/transaction_views/all_transactions_view.dart index a1f177457..1851acb4a 100644 --- a/lib/pages/wallet_view/transaction_views/all_transactions_view.dart +++ b/lib/pages/wallet_view/transaction_views/all_transactions_view.dart @@ -31,10 +31,11 @@ import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount_formatter.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/format.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/epiccash.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; import 'package:stackwallet/widgets/conditional_parent.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; @@ -58,9 +59,9 @@ typedef _GroupedTransactions = ({ class AllTransactionsView extends ConsumerStatefulWidget { const AllTransactionsView({ - Key? key, + super.key, required this.walletId, - }) : super(key: key); + }); static const String routeName = "/allTransactions"; @@ -830,10 +831,10 @@ class TransactionFilterOptionBarItem extends StatelessWidget { class DesktopTransactionCardRow extends ConsumerStatefulWidget { const DesktopTransactionCardRow({ - Key? key, + super.key, required this.transaction, required this.walletId, - }) : super(key: key); + }); final Transaction transaction; final String walletId; @@ -849,8 +850,8 @@ class _DesktopTransactionCardRowState late final String walletId; late final int minConfirms; - String whatIsIt(TransactionType type, Coin coin, int height) { - if (coin == Coin.epicCash && _transaction.slateId == null) { + String whatIsIt(TransactionType type, CryptoCurrency coin, int height) { + if (coin is Epiccash && _transaction.slateId == null) { return "Restored Funds"; } @@ -934,7 +935,7 @@ class _DesktopTransactionCardRowState ), ), onPressed: () async { - if (coin == Coin.epicCash && _transaction.slateId == null) { + if (coin is Epiccash && _transaction.slateId == null) { unawaited( showFloatingFlushBar( context: context, diff --git a/lib/pages/wallet_view/transaction_views/transaction_details_view.dart b/lib/pages/wallet_view/transaction_views/transaction_details_view.dart index 82a29b087..a0d6afff2 100644 --- a/lib/pages/wallet_view/transaction_views/transaction_details_view.dart +++ b/lib/pages/wallet_view/transaction_views/transaction_details_view.dart @@ -32,11 +32,19 @@ import 'package:stackwallet/utilities/amount/amount_formatter.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/block_explorers.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/format.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/bitcoincash.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/ecash.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/epiccash.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/ethereum.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/monero.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/wownero.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; +import 'package:stackwallet/wallets/crypto_currency/intermediate/nano_currency.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; import 'package:stackwallet/wallets/wallet/impl/epiccash_wallet.dart'; import 'package:stackwallet/widgets/background.dart'; @@ -56,17 +64,17 @@ import 'package:url_launcher/url_launcher.dart'; class TransactionDetailsView extends ConsumerStatefulWidget { const TransactionDetailsView({ - Key? key, + super.key, required this.transaction, required this.walletId, required this.coin, - }) : super(key: key); + }); static const String routeName = "/transactionDetails"; final Transaction transaction; final String walletId; - final Coin coin; + final CryptoCurrency coin; @override ConsumerState<TransactionDetailsView> createState() => @@ -79,7 +87,7 @@ class _TransactionDetailsViewState late Transaction _transaction; late final String walletId; - late final Coin coin; + late final CryptoCurrency coin; late final Amount amount; late final Amount fee; late final String amountPrefix; @@ -104,10 +112,9 @@ class _TransactionDetailsViewState .minConfirms; coin = widget.coin; amount = _transaction.realAmount; - fee = _transaction.fee.toAmountAsRaw(fractionDigits: coin.decimals); + fee = _transaction.fee.toAmountAsRaw(fractionDigits: coin.fractionDigits); - if ((coin == Coin.firo || coin == Coin.firoTestNet) && - _transaction.subType == TransactionSubType.mint) { + if ((coin is Firo) && _transaction.subType == TransactionSubType.mint) { amountPrefix = ""; } else { amountPrefix = _transaction.type == TransactionType.outgoing ? "-" : "+"; @@ -119,7 +126,7 @@ class _TransactionDetailsViewState unit = isTokenTx ? ethContract!.symbol : coin.ticker; - // if (coin == Coin.firo || coin == Coin.firoTestNet) { + // if (coin is Firo) { // showFeePending = true; // } else { // showFeePending = false; @@ -134,7 +141,7 @@ class _TransactionDetailsViewState String whatIsIt(Transaction tx, int height) { final type = tx.type; - if (coin == Coin.firo || coin == Coin.firoTestNet) { + if (coin is Firo) { if (tx.subType == TransactionSubType.mint) { if (tx.isConfirmed(height, minConfirms)) { return "Minted"; @@ -144,7 +151,7 @@ class _TransactionDetailsViewState } } - if (coin == Coin.epicCash) { + if (coin is Epiccash) { if (_transaction.isCancelled) { return "Cancelled"; } else if (type == TransactionType.incoming) { @@ -202,9 +209,10 @@ class _TransactionDetailsViewState } try { final contacts = ref.read(addressBookServiceProvider).contacts.where( - (element) => element.addresses - .where((element) => element.address == address) - .isNotEmpty); + (element) => element.addresses + .where((element) => element.address == address) + .isNotEmpty, + ); if (contacts.isNotEmpty) { return contacts.first.name; } else { @@ -218,20 +226,23 @@ class _TransactionDetailsViewState Future<bool> showExplorerWarning(String explorer) async { final bool? shouldContinue = await showDialog<bool>( - context: context, - barrierDismissible: false, - builder: (_) { - if (!isDesktop) { - return StackDialog( - title: "Attention", - message: - "You are about to view this transaction in a block explorer. The explorer may log your IP address and link it to the transaction. Only proceed if you trust $explorer.", - icon: Row( - children: [ - Consumer(builder: (_, ref, __) { + context: context, + barrierDismissible: false, + builder: (_) { + if (!isDesktop) { + return StackDialog( + title: "Attention", + message: + "You are about to view this transaction in a block explorer. The explorer may log your IP address and link it to the transaction. Only proceed if you trust $explorer.", + icon: Row( + children: [ + Consumer( + builder: (_, ref, __) { return Checkbox( - value: ref.watch(prefsChangeNotifierProvider - .select((value) => value.hideBlockExplorerWarning)), + value: ref.watch( + prefsChangeNotifierProvider + .select((value) => value.hideBlockExplorerWarning), + ), onChanged: (value) { if (value is bool) { ref @@ -241,61 +252,65 @@ class _TransactionDetailsViewState } }, ); - }), - Text( - "Never show again", - style: STextStyles.smallMed14(context), - ) - ], - ), - leftButton: TextButton( - onPressed: () { - Navigator.of(context).pop(false); - }, - child: Text( - "Cancel", - style: STextStyles.button(context).copyWith( - color: Theme.of(context) - .extension<StackColors>()! - .accentColorDark), + }, + ), + Text( + "Never show again", + style: STextStyles.smallMed14(context), + ), + ], + ), + leftButton: TextButton( + onPressed: () { + Navigator.of(context).pop(false); + }, + child: Text( + "Cancel", + style: STextStyles.button(context).copyWith( + color: Theme.of(context) + .extension<StackColors>()! + .accentColorDark, ), ), - rightButton: TextButton( - style: Theme.of(context) - .extension<StackColors>()! - .getPrimaryEnabledButtonStyle(context), - onPressed: () { - Navigator.of(context).pop(true); - }, - child: Text( - "Continue", - style: STextStyles.button(context), - ), + ), + rightButton: TextButton( + style: Theme.of(context) + .extension<StackColors>()! + .getPrimaryEnabledButtonStyle(context), + onPressed: () { + Navigator.of(context).pop(true); + }, + child: Text( + "Continue", + style: STextStyles.button(context), ), - ); - } else { - return DesktopDialog( - maxWidth: 550, - maxHeight: 300, - child: Padding( - padding: - const EdgeInsets.symmetric(horizontal: 32, vertical: 20), - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - "Attention", - style: STextStyles.desktopH2(context), - ), - Row( - children: [ - Consumer(builder: (_, ref, __) { + ), + ); + } else { + return DesktopDialog( + maxWidth: 550, + maxHeight: 300, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 20), + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "Attention", + style: STextStyles.desktopH2(context), + ), + Row( + children: [ + Consumer( + builder: (_, ref, __) { return Checkbox( - value: ref.watch(prefsChangeNotifierProvider - .select((value) => - value.hideBlockExplorerWarning)), + value: ref.watch( + prefsChangeNotifierProvider.select( + (value) => value.hideBlockExplorerWarning, + ), + ), onChanged: (value) { if (value is bool) { ref @@ -305,55 +320,57 @@ class _TransactionDetailsViewState } }, ); - }), - Text( - "Never show again", - style: STextStyles.smallMed14(context), - ) - ], - ), - ], - ), - const SizedBox(height: 16), - Text( - "You are about to view this transaction in a block explorer. The explorer may log your IP address and link it to the transaction. Only proceed if you trust $explorer.", - style: STextStyles.desktopTextSmall(context), - ), - const SizedBox(height: 35), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SecondaryButton( - width: 200, - buttonHeight: ButtonHeight.l, - label: "Cancel", - onPressed: () { - Navigator.of( - context, - rootNavigator: true, - ).pop(false); - }, - ), - const SizedBox(width: 20), - PrimaryButton( - width: 200, - buttonHeight: ButtonHeight.l, - label: "Continue", - onPressed: () { - Navigator.of( - context, - rootNavigator: true, - ).pop(true); - }, - ), - ], - ), - ], - ), + }, + ), + Text( + "Never show again", + style: STextStyles.smallMed14(context), + ), + ], + ), + ], + ), + const SizedBox(height: 16), + Text( + "You are about to view this transaction in a block explorer. The explorer may log your IP address and link it to the transaction. Only proceed if you trust $explorer.", + style: STextStyles.desktopTextSmall(context), + ), + const SizedBox(height: 35), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SecondaryButton( + width: 200, + buttonHeight: ButtonHeight.l, + label: "Cancel", + onPressed: () { + Navigator.of( + context, + rootNavigator: true, + ).pop(false); + }, + ), + const SizedBox(width: 20), + PrimaryButton( + width: 200, + buttonHeight: ButtonHeight.l, + label: "Continue", + onPressed: () { + Navigator.of( + context, + rootNavigator: true, + ).pop(true); + }, + ), + ], + ), + ], ), - ); - } - }); + ), + ); + } + }, + ); return shouldContinue ?? false; } @@ -474,7 +491,7 @@ class _TransactionDetailsViewState ), SelectableText( _transaction.isCancelled - ? coin == Coin.ethereum + ? coin is Ethereum ? "Failed" : "Cancelled" : whatIsIt( @@ -483,7 +500,8 @@ class _TransactionDetailsViewState ), style: STextStyles.desktopTextMedium( - context), + context, + ), ), ], ), @@ -496,37 +514,43 @@ class _TransactionDetailsViewState "$amountPrefix${ref.watch(pAmountFormatter(coin)).format(amount, ethContract: ethContract)}", style: isDesktop ? STextStyles - .desktopTextExtraExtraSmall( - context) - .copyWith( + .desktopTextExtraExtraSmall( + context, + ).copyWith( color: Theme.of(context) .extension< StackColors>()! .textDark, ) : STextStyles.titleBold12( - context), + context, + ), ), const SizedBox( height: 2, ), if (ref.watch( - prefsChangeNotifierProvider - .select((value) => - value.externalCalls))) + prefsChangeNotifierProvider.select( + (value) => value.externalCalls, + ), + )) SelectableText( "$amountPrefix${(amount.decimal * ref.watch( - priceAnd24hChangeNotifierProvider.select( - (value) => isTokenTx - ? value - .getTokenPrice( - _transaction - .otherData!) - .item1 - : value - .getPrice( - coin) - .item1), + priceAnd24hChangeNotifierProvider + .select( + (value) => isTokenTx + ? value + .getTokenPrice( + _transaction + .otherData!, + ) + .item1 + : value + .getPrice( + coin, + ) + .item1, + ), )).toAmount(fractionDigits: 2).fiatString( locale: ref.watch( localeServiceChangeNotifierProvider @@ -543,9 +567,11 @@ class _TransactionDetailsViewState style: isDesktop ? STextStyles .desktopTextExtraExtraSmall( - context) + context, + ) : STextStyles.itemSubtitle( - context), + context, + ), ), ], ), @@ -587,7 +613,7 @@ class _TransactionDetailsViewState // child: SelectableText( _transaction.isCancelled - ? coin == Coin.ethereum + ? coin is Ethereum ? "Failed" : "Cancelled" : whatIsIt( @@ -596,9 +622,9 @@ class _TransactionDetailsViewState ), style: isDesktop ? STextStyles - .desktopTextExtraExtraSmall( - context) - .copyWith( + .desktopTextExtraExtraSmall( + context, + ).copyWith( color: _transaction.type == TransactionType.outgoing ? Theme.of(context) @@ -615,12 +641,10 @@ class _TransactionDetailsViewState ], ), ), - if (!((coin == Coin.monero || - coin == Coin.wownero) && + if (!((coin is Monero || coin is Wownero) && _transaction.type == TransactionType.outgoing) && - !((coin == Coin.firo || - coin == Coin.firoTestNet) && + !((coin is Firo) && _transaction.subType == TransactionSubType.mint)) isDesktop @@ -628,12 +652,10 @@ class _TransactionDetailsViewState : const SizedBox( height: 12, ), - if (!((coin == Coin.monero || - coin == Coin.wownero) && + if (!((coin is Monero || coin is Wownero) && _transaction.type == TransactionType.outgoing) && - !((coin == Coin.firo || - coin == Coin.firoTestNet) && + !((coin is Firo) && _transaction.subType == TransactionSubType.mint)) RoundedWhiteContainer( @@ -694,7 +716,7 @@ class _TransactionDetailsViewState ); } }, - ) + ), ], ); }, @@ -706,9 +728,11 @@ class _TransactionDetailsViewState style: isDesktop ? STextStyles .desktopTextExtraExtraSmall( - context) + context, + ) : STextStyles.itemSubtitle( - context), + context, + ), ), ), const SizedBox( @@ -718,11 +742,14 @@ class _TransactionDetailsViewState TransactionType.incoming ? FutureBuilder( future: fetchContactNameFor( - _transaction.address - .value!.value), - builder: (builderContext, - AsyncSnapshot<String> - snapshot) { + _transaction + .address.value!.value, + ), + builder: ( + builderContext, + AsyncSnapshot<String> + snapshot, + ) { String addressOrContactName = _transaction.address @@ -738,18 +765,20 @@ class _TransactionDetailsViewState addressOrContactName, style: isDesktop ? STextStyles - .desktopTextExtraExtraSmall( - context) - .copyWith( + .desktopTextExtraExtraSmall( + context, + ).copyWith( color: Theme.of( - context) + context, + ) .extension< StackColors>()! .textDark, ) : STextStyles .itemSubtitle12( - context), + context, + ), ); }, ) @@ -758,18 +787,20 @@ class _TransactionDetailsViewState .address.value!.value, style: isDesktop ? STextStyles - .desktopTextExtraExtraSmall( - context) - .copyWith( + .desktopTextExtraExtraSmall( + context, + ).copyWith( color: Theme.of( - context) + context, + ) .extension< StackColors>()! .textDark, ) : STextStyles .itemSubtitle12( - context), + context, + ), ), ], ), @@ -781,13 +812,13 @@ class _TransactionDetailsViewState ], ), ), - if (coin == Coin.epicCash) + if (coin is Epiccash) isDesktop ? const _Divider() : const SizedBox( height: 12, ), - if (coin == Coin.epicCash) + if (coin is Epiccash) RoundedWhiteContainer( padding: isDesktop ? const EdgeInsets.all(16) @@ -807,9 +838,11 @@ class _TransactionDetailsViewState style: isDesktop ? STextStyles .desktopTextExtraExtraSmall( - context) + context, + ) : STextStyles.itemSubtitle( - context), + context, + ), ), const SizedBox( height: 8, @@ -818,16 +851,17 @@ class _TransactionDetailsViewState _transaction.otherData ?? "", style: isDesktop ? STextStyles - .desktopTextExtraExtraSmall( - context) - .copyWith( + .desktopTextExtraExtraSmall( + context, + ).copyWith( color: Theme.of(context) .extension< StackColors>()! .textDark, ) : STextStyles.itemSubtitle12( - context), + context, + ), ), ], ), @@ -856,13 +890,14 @@ class _TransactionDetailsViewState MainAxisAlignment.spaceBetween, children: [ Text( - (coin == Coin.epicCash) + (coin is Epiccash) ? "Local Note" : "Note ", style: isDesktop ? STextStyles .desktopTextExtraExtraSmall( - context) + context, + ) : STextStyles.itemSubtitle(context), ), isDesktop @@ -910,7 +945,8 @@ class _TransactionDetailsViewState Text( "Edit", style: STextStyles.link2( - context), + context, + ), ), ], ), @@ -934,9 +970,9 @@ class _TransactionDetailsViewState "", style: isDesktop ? STextStyles - .desktopTextExtraExtraSmall( - context) - .copyWith( + .desktopTextExtraExtraSmall( + context, + ).copyWith( color: Theme.of(context) .extension<StackColors>()! .textDark, @@ -969,7 +1005,8 @@ class _TransactionDetailsViewState style: isDesktop ? STextStyles .desktopTextExtraExtraSmall( - context) + context, + ) : STextStyles.itemSubtitle(context), ), if (isDesktop) @@ -983,15 +1020,16 @@ class _TransactionDetailsViewState ), style: isDesktop ? STextStyles - .desktopTextExtraExtraSmall( - context) - .copyWith( + .desktopTextExtraExtraSmall( + context, + ).copyWith( color: Theme.of(context) .extension<StackColors>()! .textDark, ) : STextStyles.itemSubtitle12( - context), + context, + ), ), ], ), @@ -1002,9 +1040,9 @@ class _TransactionDetailsViewState ), style: isDesktop ? STextStyles - .desktopTextExtraExtraSmall( - context) - .copyWith( + .desktopTextExtraExtraSmall( + context, + ).copyWith( color: Theme.of(context) .extension<StackColors>()! .textDark, @@ -1020,36 +1058,138 @@ class _TransactionDetailsViewState ], ), ), - if (coin != Coin.banano && coin != Coin.nano) + if (coin is! NanoCurrency) isDesktop ? const _Divider() : const SizedBox( height: 12, ), - if (coin != Coin.banano && coin != Coin.nano) + if (coin is! NanoCurrency) RoundedWhiteContainer( padding: isDesktop ? const EdgeInsets.all(16) : const EdgeInsets.all(12), - child: Builder(builder: (context) { - String feeString = showFeePending - ? _transaction.isConfirmed( - currentHeight, - minConfirms, - ) - ? ref - .watch(pAmountFormatter(coin)) - .format( - fee, - withUnitName: isTokenTx, - ) - : "Pending" - : ref - .watch(pAmountFormatter(coin)) - .format( - fee, - withUnitName: isTokenTx, - ); + child: Builder( + builder: (context) { + String feeString = showFeePending + ? _transaction.isConfirmed( + currentHeight, + minConfirms, + ) + ? ref + .watch(pAmountFormatter(coin)) + .format( + fee, + withUnitName: isTokenTx, + ) + : "Pending" + : ref + .watch(pAmountFormatter(coin)) + .format( + fee, + withUnitName: isTokenTx, + ); + + return Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + "Transaction fee", + style: isDesktop + ? STextStyles + .desktopTextExtraExtraSmall( + context, + ) + : STextStyles.itemSubtitle( + context, + ), + ), + if (isDesktop) + const SizedBox( + height: 2, + ), + if (isDesktop) + SelectableText( + feeString, + style: isDesktop + ? STextStyles + .desktopTextExtraExtraSmall( + context, + ).copyWith( + color: Theme.of(context) + .extension< + StackColors>()! + .textDark, + ) + : STextStyles + .itemSubtitle12( + context, + ), + ), + ], + ), + if (!isDesktop) + SelectableText( + feeString, + style: isDesktop + ? STextStyles + .desktopTextExtraExtraSmall( + context, + ).copyWith( + color: Theme.of(context) + .extension< + StackColors>()! + .textDark, + ) + : STextStyles.itemSubtitle12( + context, + ), + ), + if (isDesktop) + IconCopyButton(data: feeString), + ], + ); + }, + ), + ), + isDesktop + ? const _Divider() + : const SizedBox( + height: 12, + ), + RoundedWhiteContainer( + padding: isDesktop + ? const EdgeInsets.all(16) + : const EdgeInsets.all(12), + child: Builder( + builder: (context) { + final String height; + + if (widget.coin is Bitcoincash || + widget.coin is Ecash) { + height = + "${_transaction.height != null && _transaction.height! > 0 ? _transaction.height! : "Pending"}"; + } else { + height = widget.coin is! Epiccash && + _transaction.isConfirmed( + currentHeight, + minConfirms, + ) + ? "${_transaction.height == 0 ? "Unknown" : _transaction.height}" + : _transaction.getConfirmations( + currentHeight, + ) > + 0 + ? "${_transaction.height}" + : "Pending"; + } return Row( mainAxisAlignment: @@ -1062,13 +1202,15 @@ class _TransactionDetailsViewState CrossAxisAlignment.start, children: [ Text( - "Transaction fee", + "Block height", style: isDesktop ? STextStyles .desktopTextExtraExtraSmall( - context) + context, + ) : STextStyles.itemSubtitle( - context), + context, + ), ), if (isDesktop) const SizedBox( @@ -1076,141 +1218,53 @@ class _TransactionDetailsViewState ), if (isDesktop) SelectableText( - feeString, + height, style: isDesktop ? STextStyles - .desktopTextExtraExtraSmall( - context) - .copyWith( + .desktopTextExtraExtraSmall( + context, + ).copyWith( color: Theme.of(context) .extension< StackColors>()! .textDark, ) : STextStyles.itemSubtitle12( - context), + context, + ), ), ], ), if (!isDesktop) SelectableText( - feeString, + height, style: isDesktop ? STextStyles - .desktopTextExtraExtraSmall( - context) - .copyWith( + .desktopTextExtraExtraSmall( + context, + ).copyWith( color: Theme.of(context) .extension<StackColors>()! .textDark, ) : STextStyles.itemSubtitle12( - context), + context, + ), ), if (isDesktop) - IconCopyButton(data: feeString) + IconCopyButton(data: height), ], ); - }), + }, ), - isDesktop - ? const _Divider() - : const SizedBox( - height: 12, - ), - RoundedWhiteContainer( - padding: isDesktop - ? const EdgeInsets.all(16) - : const EdgeInsets.all(12), - child: Builder(builder: (context) { - final String height; - - if (widget.coin == Coin.bitcoincash || - widget.coin == Coin.eCash || - widget.coin == Coin.bitcoincashTestnet) { - height = - "${_transaction.height != null && _transaction.height! > 0 ? _transaction.height! : "Pending"}"; - } else { - height = widget.coin != Coin.epicCash && - _transaction.isConfirmed( - currentHeight, - minConfirms, - ) - ? "${_transaction.height == 0 ? "Unknown" : _transaction.height}" - : _transaction.getConfirmations( - currentHeight) > - 0 - ? "${_transaction.height}" - : "Pending"; - } - - return Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Text( - "Block height", - style: isDesktop - ? STextStyles - .desktopTextExtraExtraSmall( - context) - : STextStyles.itemSubtitle( - context), - ), - if (isDesktop) - const SizedBox( - height: 2, - ), - if (isDesktop) - SelectableText( - height, - style: isDesktop - ? STextStyles - .desktopTextExtraExtraSmall( - context) - .copyWith( - color: Theme.of(context) - .extension< - StackColors>()! - .textDark, - ) - : STextStyles.itemSubtitle12( - context), - ), - ], - ), - if (!isDesktop) - SelectableText( - height, - style: isDesktop - ? STextStyles - .desktopTextExtraExtraSmall( - context) - .copyWith( - color: Theme.of(context) - .extension<StackColors>()! - .textDark, - ) - : STextStyles.itemSubtitle12( - context), - ), - if (isDesktop) IconCopyButton(data: height), - ], - ); - }), ), - if (coin == Coin.ethereum) + if (coin is Ethereum) isDesktop ? const _Divider() : const SizedBox( height: 12, ), - if (coin == Coin.ethereum) + if (coin is Ethereum) RoundedWhiteContainer( padding: isDesktop ? const EdgeInsets.all(16) @@ -1225,16 +1279,17 @@ class _TransactionDetailsViewState style: isDesktop ? STextStyles .desktopTextExtraExtraSmall( - context) + context, + ) : STextStyles.itemSubtitle(context), ), SelectableText( _transaction.nonce.toString(), style: isDesktop ? STextStyles - .desktopTextExtraExtraSmall( - context) - .copyWith( + .desktopTextExtraExtraSmall( + context, + ).copyWith( color: Theme.of(context) .extension<StackColors>()! .textDark, @@ -1265,16 +1320,17 @@ class _TransactionDetailsViewState style: isDesktop ? STextStyles .desktopTextExtraExtraSmall( - context) + context, + ) : STextStyles.itemSubtitle(context), ), SelectableText( _transaction.subType.toString(), style: isDesktop ? STextStyles - .desktopTextExtraExtraSmall( - context) - .copyWith( + .desktopTextExtraExtraSmall( + context, + ).copyWith( color: Theme.of(context) .extension<StackColors>()! .textDark, @@ -1308,9 +1364,11 @@ class _TransactionDetailsViewState style: isDesktop ? STextStyles .desktopTextExtraExtraSmall( - context) + context, + ) : STextStyles.itemSubtitle( - context), + context, + ), ), const SizedBox( height: 8, @@ -1323,21 +1381,22 @@ class _TransactionDetailsViewState _transaction.txid, style: isDesktop ? STextStyles - .desktopTextExtraExtraSmall( - context) - .copyWith( + .desktopTextExtraExtraSmall( + context, + ).copyWith( color: Theme.of(context) .extension<StackColors>()! .textDark, ) : STextStyles.itemSubtitle12( - context), + context, + ), ), - if (coin != Coin.epicCash) + if (coin is! Epiccash) const SizedBox( height: 8, ), - if (coin != Coin.epicCash) + if (coin is! Epiccash) CustomTextButton( text: "Open in block explorer", onTap: () async { @@ -1349,12 +1408,14 @@ class _TransactionDetailsViewState if (ref .read( - prefsChangeNotifierProvider) + prefsChangeNotifierProvider, + ) .hideBlockExplorerWarning == false) { final shouldContinue = await showExplorerWarning( - "${uri.scheme}://${uri.host}"); + "${uri.scheme}://${uri.host}", + ); if (!shouldContinue) { return; @@ -1415,12 +1476,12 @@ class _TransactionDetailsViewState ], ), ), - // if ((coin == Coin.firoTestNet || coin == Coin.firo) && + // if ((coin is FiroTestNet || coin is Firo) && // _transaction.subType == "mint") // const SizedBox( // height: 12, // ), - // if ((coin == Coin.firoTestNet || coin == Coin.firo) && + // if ((coin is FiroTestNet || coin is Firo) && // _transaction.subType == "mint") // RoundedWhiteContainer( // child: Column( @@ -1492,13 +1553,13 @@ class _TransactionDetailsViewState // ], // ), // ), - if (coin == Coin.epicCash) + if (coin is Epiccash) isDesktop ? const _Divider() : const SizedBox( height: 12, ), - if (coin == Coin.epicCash) + if (coin is Epiccash) RoundedWhiteContainer( padding: isDesktop ? const EdgeInsets.all(16) @@ -1517,9 +1578,11 @@ class _TransactionDetailsViewState style: isDesktop ? STextStyles .desktopTextExtraExtraSmall( - context) + context, + ) : STextStyles.itemSubtitle( - context), + context, + ), ), // Flexible( // child: FittedBox( @@ -1529,15 +1592,16 @@ class _TransactionDetailsViewState _transaction.slateId ?? "Unknown", style: isDesktop ? STextStyles - .desktopTextExtraExtraSmall( - context) - .copyWith( + .desktopTextExtraExtraSmall( + context, + ).copyWith( color: Theme.of(context) .extension<StackColors>()! .textDark, ) : STextStyles.itemSubtitle12( - context), + context, + ), ), // ), // ), @@ -1569,7 +1633,7 @@ class _TransactionDetailsViewState ), ), floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, - floatingActionButton: (coin == Coin.epicCash && + floatingActionButton: (coin is Epiccash && _transaction.getConfirmations(currentHeight) < 1 && _transaction.isCancelled == false) ? ConditionalParent( @@ -1595,20 +1659,24 @@ class _TransactionDetailsViewState if (wallet is EpiccashWallet) { final String? id = _transaction.slateId; if (id == null) { - unawaited(showFloatingFlushBar( - type: FlushBarType.warning, - message: "Could not find Epic transaction ID", - context: context, - )); + unawaited( + showFloatingFlushBar( + type: FlushBarType.warning, + message: "Could not find Epic transaction ID", + context: context, + ), + ); return; } - unawaited(showDialog<dynamic>( - barrierDismissible: false, - context: context, - builder: (_) => - const CancellingTransactionProgressDialog(), - )); + unawaited( + showDialog<dynamic>( + barrierDismissible: false, + context: context, + builder: (_) => + const CancellingTransactionProgressDialog(), + ), + ); final result = await wallet.cancelPendingTransactionAndPost(id); @@ -1624,8 +1692,10 @@ class _TransactionDetailsViewState onOkPressed: (_) { wallet.refresh(); Navigator.of(context).popUntil( - ModalRoute.withName( - WalletView.routeName)); + ModalRoute.withName( + WalletView.routeName, + ), + ); }, ), ); @@ -1640,11 +1710,13 @@ class _TransactionDetailsViewState } } } else { - unawaited(showFloatingFlushBar( - type: FlushBarType.warning, - message: "ERROR: Wallet type is not Epic Cash", - context: context, - )); + unawaited( + showFloatingFlushBar( + type: FlushBarType.warning, + message: "ERROR: Wallet type is not Epic Cash", + context: context, + ), + ); return; } }, diff --git a/lib/pages/wallet_view/transaction_views/transaction_search_filter_view.dart b/lib/pages/wallet_view/transaction_views/transaction_search_filter_view.dart index 10d34771c..84bb7c2af 100644 --- a/lib/pages/wallet_view/transaction_views/transaction_search_filter_view.dart +++ b/lib/pages/wallet_view/transaction_views/transaction_search_filter_view.dart @@ -22,10 +22,10 @@ import 'package:stackwallet/utilities/amount/amount_formatter.dart'; import 'package:stackwallet/utilities/amount/amount_input_formatter.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/format.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/background.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/date_picker/date_picker.dart'; @@ -46,7 +46,7 @@ class TransactionSearchFilterView extends ConsumerStatefulWidget { static const String routeName = "/transactionSearchFilter"; - final Coin coin; + final CryptoCurrency coin; @override ConsumerState<TransactionSearchFilterView> createState() => @@ -665,7 +665,7 @@ class _TransactionSearchViewState ), inputFormatters: [ AmountInputFormatter( - decimals: widget.coin.decimals, + decimals: widget.coin.fractionDigits, unit: ref.watch(pAmountUnit(widget.coin)), locale: ref.watch( localeServiceChangeNotifierProvider @@ -896,9 +896,9 @@ class _TransactionSearchViewState if (amountText.isNotEmpty && !(amountText == "," || amountText == ".")) { amount = amountText.contains(",") ? Decimal.parse(amountText.replaceFirst(",", ".")) - .toAmount(fractionDigits: widget.coin.decimals) + .toAmount(fractionDigits: widget.coin.fractionDigits) : Decimal.parse(amountText) - .toAmount(fractionDigits: widget.coin.decimals); + .toAmount(fractionDigits: widget.coin.fractionDigits); } final TransactionFilter filter = TransactionFilter( diff --git a/lib/pages/wallet_view/transaction_views/tx_v2/all_transactions_v2_view.dart b/lib/pages/wallet_view/transaction_views/tx_v2/all_transactions_v2_view.dart index 50a53291f..954285f0d 100644 --- a/lib/pages/wallet_view/transaction_views/tx_v2/all_transactions_v2_view.dart +++ b/lib/pages/wallet_view/transaction_views/tx_v2/all_transactions_v2_view.dart @@ -32,7 +32,6 @@ import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount_formatter.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/format.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; @@ -59,10 +58,10 @@ typedef _GroupedTransactions = ({ class AllTransactionsV2View extends ConsumerStatefulWidget { const AllTransactionsV2View({ - Key? key, + super.key, required this.walletId, this.contractAddress, - }) : super(key: key); + }); static const String routeName = "/allTransactionsV2"; @@ -96,8 +95,10 @@ class _AllTransactionsV2ViewState extends ConsumerState<AllTransactionsV2View> { } // TODO: optimise search+filter - List<TransactionV2> filter( - {required List<TransactionV2> transactions, TransactionFilter? filter}) { + List<TransactionV2> filter({ + required List<TransactionV2> transactions, + TransactionFilter? filter, + }) { if (filter == null) { return transactions; } @@ -159,13 +160,15 @@ class _AllTransactionsV2ViewState extends ConsumerState<AllTransactionsV2View> { // check if address book name contains contains |= contacts - .where((e) => - e.addresses - .map((e) => e.address) - .toSet() - .intersection(tx.associatedAddresses()) - .isNotEmpty && - e.name.toLowerCase().contains(keyword)) + .where( + (e) => + e.addresses + .map((e) => e.address) + .toSet() + .intersection(tx.associatedAddresses()) + .isNotEmpty && + e.name.toLowerCase().contains(keyword), + ) .isNotEmpty; // check if address contains @@ -224,9 +227,9 @@ class _AllTransactionsV2ViewState extends ConsumerState<AllTransactionsV2View> { List<_GroupedTransactions> groupTransactionsByMonth( List<TransactionV2> transactions, ) { - Map<String, _GroupedTransactions> map = {}; + final Map<String, _GroupedTransactions> map = {}; - for (var tx in transactions) { + for (final tx in transactions) { final date = DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000); final monthYear = "${Constants.monthMap[date.month]} ${date.year}"; if (map[monthYear] == null) { @@ -291,9 +294,10 @@ class _AllTransactionsV2ViewState extends ConsumerState<AllTransactionsV2View> { if (FocusScope.of(context).hasFocus) { FocusScope.of(context).unfocus(); await Future<void>.delayed( - const Duration(milliseconds: 75)); + const Duration(milliseconds: 75), + ); } - if (mounted) { + if (context.mounted) { Navigator.of(context).pop(); } }, @@ -494,32 +498,35 @@ class _AllTransactionsV2ViewState extends ConsumerState<AllTransactionsV2View> { .isar .transactionV2s .buildQuery<TransactionV2>( - whereClauses: [ - IndexWhereClause.equalTo( - indexName: 'walletId', - value: [widget.walletId], - ) - ], - filter: widget.contractAddress == null - ? ref - .watch(pWallets) - .getWallet(widget.walletId) - .transactionFilterOperation - : ref - .read(pCurrentTokenWallet)! - .transactionFilterOperation, - sortBy: [ - const SortProperty( - property: "timestamp", - sort: Sort.desc, - ), - ]) + whereClauses: [ + IndexWhereClause.equalTo( + indexName: 'walletId', + value: [widget.walletId], + ), + ], + filter: widget.contractAddress == null + ? ref + .watch(pWallets) + .getWallet(widget.walletId) + .transactionFilterOperation + : ref + .read(pCurrentTokenWallet)! + .transactionFilterOperation, + sortBy: [ + const SortProperty( + property: "timestamp", + sort: Sort.desc, + ), + ], + ) .findAll(), builder: (_, AsyncSnapshot<List<TransactionV2>> snapshot) { if (snapshot.connectionState == ConnectionState.done && snapshot.hasData) { final filtered = filter( - transactions: snapshot.data!, filter: criteria); + transactions: snapshot.data!, + filter: criteria, + ); final searched = search(_searchString, filtered); searched.sort((a, b) { @@ -571,7 +578,8 @@ class _AllTransactionsV2ViewState extends ConsumerState<AllTransactionsV2View> { padding: const EdgeInsets.all(4), child: DesktopTransactionCardRow( key: Key( - "transactionCard_key_${month.transactions[index].txid}"), + "transactionCard_key_${month.transactions[index].txid}", + ), transaction: month.transactions[index], walletId: walletId, @@ -587,7 +595,8 @@ class _AllTransactionsV2ViewState extends ConsumerState<AllTransactionsV2View> { ...month.transactions.map( (tx) => TransactionCardV2( key: Key( - "transactionCard_key_${tx.txid}"), + "transactionCard_key_${tx.txid}", + ), transaction: tx, ), ), @@ -789,9 +798,10 @@ class TransactionFilterOptionBarItem extends StatelessWidget { child: Container( height: 32, decoration: BoxDecoration( - color: - Theme.of(context).extension<StackColors>()!.buttonBackSecondary, - borderRadius: BorderRadius.circular(1000)), + color: + Theme.of(context).extension<StackColors>()!.buttonBackSecondary, + borderRadius: BorderRadius.circular(1000), + ), child: Padding( padding: const EdgeInsets.symmetric( horizontal: 14, @@ -882,7 +892,8 @@ class _DesktopTransactionCardRowState @override Widget build(BuildContext context) { final locale = ref.watch( - localeServiceChangeNotifierProvider.select((value) => value.locale)); + localeServiceChangeNotifierProvider.select((value) => value.locale), + ); final baseCurrency = ref .watch(prefsChangeNotifierProvider.select((value) => value.currency)); @@ -890,8 +901,10 @@ class _DesktopTransactionCardRowState final coin = ref.watch(pWalletCoin(walletId)); final price = ref - .watch(priceAnd24hChangeNotifierProvider - .select((value) => value.getPrice(coin))) + .watch( + priceAnd24hChangeNotifierProvider + .select((value) => value.getPrice(coin)), + ) .item1; late final String prefix; @@ -910,42 +923,48 @@ class _DesktopTransactionCardRowState final currentHeight = ref.watch(pWalletChainHeight(walletId)); final Amount amount; - final fractionDigits = ethContract?.decimals ?? coin.decimals; + final fractionDigits = ethContract?.decimals ?? coin.fractionDigits; if (_transaction.subType == TransactionSubType.cashFusion) { amount = _transaction.getAmountReceivedInThisWallet( - fractionDigits: fractionDigits); + fractionDigits: fractionDigits, + ); } else { switch (_transaction.type) { case TransactionType.outgoing: amount = _transaction.getAmountSentFromThisWallet( - fractionDigits: fractionDigits); + fractionDigits: fractionDigits, + ); break; case TransactionType.incoming: case TransactionType.sentToSelf: if (_transaction.subType == TransactionSubType.sparkMint) { amount = _transaction.getAmountSparkSelfMinted( - fractionDigits: fractionDigits); + fractionDigits: fractionDigits, + ); } else if (_transaction.subType == TransactionSubType.sparkSpend) { final changeAddress = (ref.watch(pWallets).getWallet(walletId) as SparkInterface) .sparkChangeAddress; amount = Amount( rawValue: _transaction.outputs - .where((e) => - e.walletOwns && !e.addresses.contains(changeAddress)) + .where( + (e) => e.walletOwns && !e.addresses.contains(changeAddress), + ) .fold(BigInt.zero, (p, e) => p + e.value), - fractionDigits: coin.decimals, + fractionDigits: coin.fractionDigits, ); } else { amount = _transaction.getAmountReceivedInThisWallet( - fractionDigits: fractionDigits); + fractionDigits: fractionDigits, + ); } break; case TransactionType.unknown: amount = _transaction.getAmountSentFromThisWallet( - fractionDigits: fractionDigits); + fractionDigits: fractionDigits, + ); break; } } @@ -1043,8 +1062,10 @@ class _DesktopTransactionCardRowState ), ), ), - if (ref.watch(prefsChangeNotifierProvider - .select((value) => value.externalCalls))) + if (ref.watch( + prefsChangeNotifierProvider + .select((value) => value.externalCalls), + )) Expanded( flex: 4, child: Text( diff --git a/lib/pages/wallet_view/transaction_views/tx_v2/fusion_group_details_view.dart b/lib/pages/wallet_view/transaction_views/tx_v2/fusion_group_details_view.dart index 874d1fdba..b0094539f 100644 --- a/lib/pages/wallet_view/transaction_views/tx_v2/fusion_group_details_view.dart +++ b/lib/pages/wallet_view/transaction_views/tx_v2/fusion_group_details_view.dart @@ -14,9 +14,9 @@ import 'package:stackwallet/models/isar/models/blockchain_data/v2/transaction_v2 import 'package:stackwallet/pages/wallet_view/transaction_views/tx_v2/transaction_v2_list_item.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/background.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart'; @@ -24,17 +24,17 @@ import 'package:stackwallet/widgets/rounded_white_container.dart'; class FusionGroupDetailsView extends ConsumerStatefulWidget { const FusionGroupDetailsView({ - Key? key, + super.key, required this.transactions, required this.walletId, required this.coin, - }) : super(key: key); + }); static const String routeName = "/fusionGroupDetailsView"; final List<TransactionV2> transactions; final String walletId; - final Coin coin; + final CryptoCurrency coin; @override ConsumerState<FusionGroupDetailsView> createState() => diff --git a/lib/pages/wallet_view/transaction_views/tx_v2/transaction_v2_card.dart b/lib/pages/wallet_view/transaction_views/tx_v2/transaction_v2_card.dart index 1401625c9..0ae867544 100644 --- a/lib/pages/wallet_view/transaction_views/tx_v2/transaction_v2_card.dart +++ b/lib/pages/wallet_view/transaction_views/tx_v2/transaction_v2_card.dart @@ -15,19 +15,20 @@ import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount_formatter.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/format.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/ethereum.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/spark_interface.dart'; import 'package:stackwallet/widgets/desktop/desktop_dialog.dart'; class TransactionCardV2 extends ConsumerStatefulWidget { const TransactionCardV2({ - Key? key, + super.key, required this.transaction, - }) : super(key: key); + }); final TransactionV2 transaction; @@ -40,17 +41,17 @@ class _TransactionCardStateV2 extends ConsumerState<TransactionCardV2> { late final String walletId; late final String prefix; late final String unit; - late final Coin coin; + late final CryptoCurrency coin; late final TransactionType txType; late final EthContract? tokenContract; bool get isTokenTx => tokenContract != null; String whatIsIt( - Coin coin, + CryptoCurrency coin, int currentHeight, ) => - _transaction.isCancelled && coin == Coin.ethereum + _transaction.isCancelled && coin is Ethereum ? "Failed" : _transaction.statusLabel( currentChainHeight: currentHeight, @@ -112,7 +113,7 @@ class _TransactionCardStateV2 extends ConsumerState<TransactionCardV2> { final Amount amount; - final fractionDigits = tokenContract?.decimals ?? coin.decimals; + final fractionDigits = tokenContract?.decimals ?? coin.fractionDigits; if (_transaction.subType == TransactionSubType.cashFusion) { amount = _transaction.getAmountReceivedInThisWallet( @@ -138,7 +139,7 @@ class _TransactionCardStateV2 extends ConsumerState<TransactionCardV2> { .where((e) => e.walletOwns && !e.addresses.contains(changeAddress)) .fold(BigInt.zero, (p, e) => p + e.value), - fractionDigits: coin.decimals, + fractionDigits: coin.fractionDigits, ); } else { amount = _transaction.getAmountReceivedInThisWallet( diff --git a/lib/pages/wallet_view/transaction_views/tx_v2/transaction_v2_details_view.dart b/lib/pages/wallet_view/transaction_views/tx_v2/transaction_v2_details_view.dart index 5a1ae2032..fe58b38a0 100644 --- a/lib/pages/wallet_view/transaction_views/tx_v2/transaction_v2_details_view.dart +++ b/lib/pages/wallet_view/transaction_views/tx_v2/transaction_v2_details_view.dart @@ -33,11 +33,18 @@ import 'package:stackwallet/utilities/amount/amount_formatter.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/block_explorers.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/format.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/bitcoincash.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/ecash.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/epiccash.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/monero.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/wownero.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; +import 'package:stackwallet/wallets/crypto_currency/intermediate/nano_currency.dart'; import 'package:stackwallet/wallets/isar/models/spark_coin.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; import 'package:stackwallet/wallets/wallet/impl/epiccash_wallet.dart'; @@ -59,17 +66,17 @@ import 'package:url_launcher/url_launcher.dart'; class TransactionV2DetailsView extends ConsumerStatefulWidget { const TransactionV2DetailsView({ - Key? key, + super.key, required this.transaction, required this.walletId, required this.coin, - }) : super(key: key); + }); static const String routeName = "/transactionV2Details"; final TransactionV2 transaction; final String walletId; - final Coin coin; + final CryptoCurrency coin; @override ConsumerState<TransactionV2DetailsView> createState() => @@ -82,7 +89,7 @@ class _TransactionV2DetailsViewState late TransactionV2 _transaction; late final String walletId; - late final Coin coin; + late final CryptoCurrency coin; late final Amount amount; late final Amount fee; late final String amountPrefix; @@ -120,7 +127,7 @@ class _TransactionV2DetailsViewState minConfirms = ref.read(pWallets).getWallet(walletId).cryptoCurrency.minConfirms; - final fractionDigits = ethContract?.decimals ?? coin.decimals; + final fractionDigits = ethContract?.decimals ?? coin.fractionDigits; fee = _transaction.getFee(fractionDigits: fractionDigits); @@ -136,43 +143,61 @@ class _TransactionV2DetailsViewState case TransactionType.outgoing: case TransactionType.unknown: amount = _transaction.getAmountSentFromThisWallet( - fractionDigits: fractionDigits); + fractionDigits: fractionDigits, + ); break; case TransactionType.incoming: case TransactionType.sentToSelf: amount = _transaction.getAmountReceivedInThisWallet( - fractionDigits: fractionDigits); + fractionDigits: fractionDigits, + ); break; } data = _transaction.outputs - .map((e) => ( - addresses: e.addresses, - amount: Amount(rawValue: e.value, fractionDigits: coin.decimals) - )) + .map( + (e) => ( + addresses: e.addresses, + amount: Amount( + rawValue: e.value, + fractionDigits: coin.fractionDigits, + ) + ), + ) .toList(); } else if (_transaction.subType == TransactionSubType.cashFusion) { amount = _transaction.getAmountReceivedInThisWallet( - fractionDigits: fractionDigits); + fractionDigits: fractionDigits, + ); data = _transaction.outputs .where((e) => e.walletOwns) - .map((e) => ( - addresses: e.addresses, - amount: Amount(rawValue: e.value, fractionDigits: coin.decimals) - )) + .map( + (e) => ( + addresses: e.addresses, + amount: Amount( + rawValue: e.value, + fractionDigits: coin.fractionDigits, + ) + ), + ) .toList(); } else { switch (_transaction.type) { case TransactionType.outgoing: amount = _transaction.getAmountSentFromThisWallet( - fractionDigits: fractionDigits); + fractionDigits: fractionDigits, + ); data = _transaction.outputs .where((e) => !e.walletOwns) - .map((e) => ( - addresses: e.addresses, - amount: - Amount(rawValue: e.value, fractionDigits: coin.decimals) - )) + .map( + (e) => ( + addresses: e.addresses, + amount: Amount( + rawValue: e.value, + fractionDigits: coin.fractionDigits, + ) + ), + ) .toList(); break; @@ -191,56 +216,71 @@ class _TransactionV2DetailsViewState .and() .heightEqualTo(_transaction.height) .anyOf( - _transaction.outputs - .where((e) => + _transaction.outputs + .where( + (e) => e.walletOwns && e.addresses.isEmpty && - e.scriptPubKeyHex.length >= 488) - .map((e) => e.scriptPubKeyHex.substring(2, 488)) - .toList(), - (q, element) => q.serializedCoinB64StartsWith(element)) + e.scriptPubKeyHex.length >= 488, + ) + .map((e) => e.scriptPubKeyHex.substring(2, 488)) + .toList(), + (q, element) => q.serializedCoinB64StartsWith(element), + ) .memoProperty() .findFirstSync(); } if (_transaction.subType == TransactionSubType.sparkMint) { amount = _transaction.getAmountSparkSelfMinted( - fractionDigits: fractionDigits); + fractionDigits: fractionDigits, + ); } else if (_transaction.subType == TransactionSubType.sparkSpend) { final changeAddress = (ref.read(pWallets).getWallet(walletId) as SparkInterface) .sparkChangeAddress; amount = Amount( rawValue: _transaction.outputs - .where((e) => - e.walletOwns && !e.addresses.contains(changeAddress)) + .where( + (e) => e.walletOwns && !e.addresses.contains(changeAddress), + ) .fold(BigInt.zero, (p, e) => p + e.value), - fractionDigits: coin.decimals, + fractionDigits: coin.fractionDigits, ); } else { amount = _transaction.getAmountReceivedInThisWallet( - fractionDigits: fractionDigits); + fractionDigits: fractionDigits, + ); } data = _transaction.outputs .where((e) => e.walletOwns) - .map((e) => ( - addresses: e.addresses, - amount: - Amount(rawValue: e.value, fractionDigits: coin.decimals) - )) + .map( + (e) => ( + addresses: e.addresses, + amount: Amount( + rawValue: e.value, + fractionDigits: coin.fractionDigits, + ) + ), + ) .toList(); break; case TransactionType.unknown: amount = _transaction.getAmountSentFromThisWallet( - fractionDigits: fractionDigits); + fractionDigits: fractionDigits, + ); data = _transaction.inputs .where((e) => e.walletOwns) - .map((e) => ( - addresses: e.addresses, - amount: - Amount(rawValue: e.value, fractionDigits: coin.decimals) - )) + .map( + (e) => ( + addresses: e.addresses, + amount: Amount( + rawValue: e.value, + fractionDigits: coin.fractionDigits, + ) + ), + ) .toList(); break; } @@ -265,9 +305,10 @@ class _TransactionV2DetailsViewState } try { final contacts = ref.read(addressBookServiceProvider).contacts.where( - (element) => element.addresses - .where((element) => element.address == address) - .isNotEmpty); + (element) => element.addresses + .where((element) => element.address == address) + .isNotEmpty, + ); if (contacts.isNotEmpty) { return contacts.first.name; } else { @@ -281,20 +322,23 @@ class _TransactionV2DetailsViewState Future<bool> showExplorerWarning(String explorer) async { final bool? shouldContinue = await showDialog<bool>( - context: context, - barrierDismissible: false, - builder: (_) { - if (!isDesktop) { - return StackDialog( - title: "Attention", - message: - "You are about to view this transaction in a block explorer. The explorer may log your IP address and link it to the transaction. Only proceed if you trust $explorer.", - icon: Row( - children: [ - Consumer(builder: (_, ref, __) { + context: context, + barrierDismissible: false, + builder: (_) { + if (!isDesktop) { + return StackDialog( + title: "Attention", + message: + "You are about to view this transaction in a block explorer. The explorer may log your IP address and link it to the transaction. Only proceed if you trust $explorer.", + icon: Row( + children: [ + Consumer( + builder: (_, ref, __) { return Checkbox( - value: ref.watch(prefsChangeNotifierProvider - .select((value) => value.hideBlockExplorerWarning)), + value: ref.watch( + prefsChangeNotifierProvider + .select((value) => value.hideBlockExplorerWarning), + ), onChanged: (value) { if (value is bool) { ref @@ -304,61 +348,65 @@ class _TransactionV2DetailsViewState } }, ); - }), - Text( - "Never show again", - style: STextStyles.smallMed14(context), - ) - ], - ), - leftButton: TextButton( - onPressed: () { - Navigator.of(context).pop(false); - }, - child: Text( - "Cancel", - style: STextStyles.button(context).copyWith( - color: Theme.of(context) - .extension<StackColors>()! - .accentColorDark), + }, + ), + Text( + "Never show again", + style: STextStyles.smallMed14(context), + ), + ], + ), + leftButton: TextButton( + onPressed: () { + Navigator.of(context).pop(false); + }, + child: Text( + "Cancel", + style: STextStyles.button(context).copyWith( + color: Theme.of(context) + .extension<StackColors>()! + .accentColorDark, ), ), - rightButton: TextButton( - style: Theme.of(context) - .extension<StackColors>()! - .getPrimaryEnabledButtonStyle(context), - onPressed: () { - Navigator.of(context).pop(true); - }, - child: Text( - "Continue", - style: STextStyles.button(context), - ), + ), + rightButton: TextButton( + style: Theme.of(context) + .extension<StackColors>()! + .getPrimaryEnabledButtonStyle(context), + onPressed: () { + Navigator.of(context).pop(true); + }, + child: Text( + "Continue", + style: STextStyles.button(context), ), - ); - } else { - return DesktopDialog( - maxWidth: 550, - maxHeight: 300, - child: Padding( - padding: - const EdgeInsets.symmetric(horizontal: 32, vertical: 20), - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - "Attention", - style: STextStyles.desktopH2(context), - ), - Row( - children: [ - Consumer(builder: (_, ref, __) { + ), + ); + } else { + return DesktopDialog( + maxWidth: 550, + maxHeight: 300, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 20), + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "Attention", + style: STextStyles.desktopH2(context), + ), + Row( + children: [ + Consumer( + builder: (_, ref, __) { return Checkbox( - value: ref.watch(prefsChangeNotifierProvider - .select((value) => - value.hideBlockExplorerWarning)), + value: ref.watch( + prefsChangeNotifierProvider.select( + (value) => value.hideBlockExplorerWarning, + ), + ), onChanged: (value) { if (value is bool) { ref @@ -368,55 +416,57 @@ class _TransactionV2DetailsViewState } }, ); - }), - Text( - "Never show again", - style: STextStyles.smallMed14(context), - ) - ], - ), - ], - ), - const SizedBox(height: 16), - Text( - "You are about to view this transaction in a block explorer. The explorer may log your IP address and link it to the transaction. Only proceed if you trust $explorer.", - style: STextStyles.desktopTextSmall(context), - ), - const SizedBox(height: 35), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SecondaryButton( - width: 200, - buttonHeight: ButtonHeight.l, - label: "Cancel", - onPressed: () { - Navigator.of( - context, - rootNavigator: true, - ).pop(false); - }, - ), - const SizedBox(width: 20), - PrimaryButton( - width: 200, - buttonHeight: ButtonHeight.l, - label: "Continue", - onPressed: () { - Navigator.of( - context, - rootNavigator: true, - ).pop(true); - }, - ), - ], - ), - ], - ), + }, + ), + Text( + "Never show again", + style: STextStyles.smallMed14(context), + ), + ], + ), + ], + ), + const SizedBox(height: 16), + Text( + "You are about to view this transaction in a block explorer. The explorer may log your IP address and link it to the transaction. Only proceed if you trust $explorer.", + style: STextStyles.desktopTextSmall(context), + ), + const SizedBox(height: 35), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SecondaryButton( + width: 200, + buttonHeight: ButtonHeight.l, + label: "Cancel", + onPressed: () { + Navigator.of( + context, + rootNavigator: true, + ).pop(false); + }, + ), + const SizedBox(width: 20), + PrimaryButton( + width: 200, + buttonHeight: ButtonHeight.l, + label: "Continue", + onPressed: () { + Navigator.of( + context, + rootNavigator: true, + ).pop(true); + }, + ), + ], + ), + ], ), - ); - } - }); + ), + ); + } + }, + ); return shouldContinue ?? false; } @@ -558,7 +608,8 @@ class _TransactionV2DetailsViewState ), style: STextStyles.desktopTextMedium( - context), + context, + ), ), ], ), @@ -571,32 +622,36 @@ class _TransactionV2DetailsViewState "$amountPrefix${ref.watch(pAmountFormatter(coin)).format(amount, ethContract: ethContract)}", style: isDesktop ? STextStyles - .desktopTextExtraExtraSmall( - context) - .copyWith( + .desktopTextExtraExtraSmall( + context, + ).copyWith( color: Theme.of(context) .extension< StackColors>()! .textDark, ) : STextStyles.titleBold12( - context), + context, + ), ), const SizedBox( height: 2, ), if (ref.watch( - prefsChangeNotifierProvider - .select((value) => - value.externalCalls))) + prefsChangeNotifierProvider.select( + (value) => value.externalCalls, + ), + )) SelectableText( "$amountPrefix${(amount.decimal * ref.watch( priceAnd24hChangeNotifierProvider - .select((value) => - value - .getPrice( - coin) - .item1), + .select( + (value) => value + .getPrice( + coin, + ) + .item1, + ), )).toAmount(fractionDigits: 2).fiatString( locale: ref.watch( localeServiceChangeNotifierProvider @@ -613,9 +668,11 @@ class _TransactionV2DetailsViewState style: isDesktop ? STextStyles .desktopTextExtraExtraSmall( - context) + context, + ) : STextStyles.itemSubtitle( - context), + context, + ), ), ], ), @@ -662,9 +719,9 @@ class _TransactionV2DetailsViewState ), style: isDesktop ? STextStyles - .desktopTextExtraExtraSmall( - context) - .copyWith( + .desktopTextExtraExtraSmall( + context, + ).copyWith( color: _transaction.type == TransactionType .outgoing && @@ -685,12 +742,10 @@ class _TransactionV2DetailsViewState ], ), ), - if (!((coin == Coin.monero || - coin == Coin.wownero) && + if (!((coin is Monero || coin is Wownero) && _transaction.type == TransactionType.outgoing) && - !((coin == Coin.firo || - coin == Coin.firoTestNet) && + !((coin is Firo) && _transaction.subType == TransactionSubType.mint)) isDesktop @@ -698,12 +753,10 @@ class _TransactionV2DetailsViewState : const SizedBox( height: 12, ), - if (!((coin == Coin.monero || - coin == Coin.wownero) && + if (!((coin is Monero || coin is Wownero) && _transaction.type == TransactionType.outgoing) && - !((coin == Coin.firo || - coin == Coin.firoTestNet) && + !((coin is Firo) && _transaction.subType == TransactionSubType.mint)) RoundedWhiteContainer( @@ -778,9 +831,11 @@ class _TransactionV2DetailsViewState style: isDesktop ? STextStyles .desktopTextExtraExtraSmall( - context) + context, + ) : STextStyles.itemSubtitle( - context), + context, + ), ), ), const SizedBox( @@ -795,11 +850,13 @@ class _TransactionV2DetailsViewState 1) FutureBuilder( future: fetchContactNameFor( - data.first.addresses - .first), - builder: (builderContext, - AsyncSnapshot<String> - snapshot) { + data.first.addresses.first, + ), + builder: ( + builderContext, + AsyncSnapshot<String> + snapshot, + ) { String addressOrContactName = data.first.addresses @@ -815,18 +872,20 @@ class _TransactionV2DetailsViewState addressOrContactName, style: isDesktop ? STextStyles - .desktopTextExtraExtraSmall( - context) - .copyWith( + .desktopTextExtraExtraSmall( + context, + ).copyWith( color: Theme.of( - context) + context, + ) .extension< StackColors>()! .textDark, ) : STextStyles .itemSubtitle12( - context), + context, + ), ); }, ) @@ -848,7 +907,8 @@ class _TransactionV2DetailsViewState child: Padding( padding: const EdgeInsets.all( - 8.0), + 8.0, + ), child: Column( crossAxisAlignment: CrossAxisAlignment @@ -861,11 +921,14 @@ class _TransactionV2DetailsViewState return FutureBuilder( future: fetchContactNameFor( - e), - builder: (builderContext, - AsyncSnapshot< - String> - snapshot) { + e, + ), + builder: ( + builderContext, + AsyncSnapshot< + String> + snapshot, + ) { final String addressOrContactName; if (snapshot.connectionState == @@ -909,29 +972,31 @@ class _TransactionV2DetailsViewState ], ), ), - if (coin == Coin.epicCash) + if (coin is Epiccash) RoundedWhiteContainer( padding: isDesktop ? const EdgeInsets.all(16) : const EdgeInsets.all(12), child: Row( mainAxisAlignment: - MainAxisAlignment.spaceBetween, + MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( child: Column( crossAxisAlignment: - CrossAxisAlignment.start, + CrossAxisAlignment.start, children: [ Text( "On chain note", style: isDesktop ? STextStyles - .desktopTextExtraExtraSmall( - context) + .desktopTextExtraExtraSmall( + context, + ) : STextStyles.itemSubtitle( - context), + context, + ), ), const SizedBox( height: 8, @@ -940,16 +1005,17 @@ class _TransactionV2DetailsViewState _transaction.onChainNote ?? "", style: isDesktop ? STextStyles - .desktopTextExtraExtraSmall( - context) - .copyWith( - color: Theme.of(context) - .extension< - StackColors>()! - .textDark, - ) + .desktopTextExtraExtraSmall( + context, + ).copyWith( + color: Theme.of(context) + .extension< + StackColors>()! + .textDark, + ) : STextStyles.itemSubtitle12( - context), + context, + ), ), ], ), @@ -978,13 +1044,14 @@ class _TransactionV2DetailsViewState MainAxisAlignment.spaceBetween, children: [ Text( - (coin == Coin.epicCash) + (coin is Epiccash) ? "Local Note" : "Note ", style: isDesktop ? STextStyles .desktopTextExtraExtraSmall( - context) + context, + ) : STextStyles.itemSubtitle(context), ), isDesktop @@ -1032,7 +1099,8 @@ class _TransactionV2DetailsViewState Text( "Edit", style: STextStyles.link2( - context), + context, + ), ), ], ), @@ -1047,8 +1115,9 @@ class _TransactionV2DetailsViewState .watch( pTransactionNote( ( - txid: (coin == Coin.epicCash) ? - _transaction.slateId.toString() + txid: (coin is Epiccash) + ? _transaction.slateId + .toString() : _transaction.txid, walletId: walletId ), @@ -1058,9 +1127,9 @@ class _TransactionV2DetailsViewState "", style: isDesktop ? STextStyles - .desktopTextExtraExtraSmall( - context) - .copyWith( + .desktopTextExtraExtraSmall( + context, + ).copyWith( color: Theme.of(context) .extension<StackColors>()! .textDark, @@ -1091,9 +1160,11 @@ class _TransactionV2DetailsViewState style: isDesktop ? STextStyles .desktopTextExtraExtraSmall( - context) + context, + ) : STextStyles.itemSubtitle( - context), + context, + ), ), ], ), @@ -1104,9 +1175,9 @@ class _TransactionV2DetailsViewState _sparkMemo!, style: isDesktop ? STextStyles - .desktopTextExtraExtraSmall( - context) - .copyWith( + .desktopTextExtraExtraSmall( + context, + ).copyWith( color: Theme.of(context) .extension<StackColors>()! .textDark, @@ -1139,7 +1210,8 @@ class _TransactionV2DetailsViewState style: isDesktop ? STextStyles .desktopTextExtraExtraSmall( - context) + context, + ) : STextStyles.itemSubtitle(context), ), if (isDesktop) @@ -1153,15 +1225,16 @@ class _TransactionV2DetailsViewState ), style: isDesktop ? STextStyles - .desktopTextExtraExtraSmall( - context) - .copyWith( + .desktopTextExtraExtraSmall( + context, + ).copyWith( color: Theme.of(context) .extension<StackColors>()! .textDark, ) : STextStyles.itemSubtitle12( - context), + context, + ), ), ], ), @@ -1172,9 +1245,9 @@ class _TransactionV2DetailsViewState ), style: isDesktop ? STextStyles - .desktopTextExtraExtraSmall( - context) - .copyWith( + .desktopTextExtraExtraSmall( + context, + ).copyWith( color: Theme.of(context) .extension<StackColors>()! .textDark, @@ -1190,34 +1263,136 @@ class _TransactionV2DetailsViewState ], ), ), - if (coin != Coin.banano && coin != Coin.nano) + if (coin is! NanoCurrency) isDesktop ? const _Divider() : const SizedBox( height: 12, ), - if (coin != Coin.banano && coin != Coin.nano) + if (coin is! NanoCurrency) RoundedWhiteContainer( padding: isDesktop ? const EdgeInsets.all(16) : const EdgeInsets.all(12), - child: Builder(builder: (context) { - String feeString = showFeePending - ? _transaction.isConfirmed( - currentHeight, - minConfirms, - ) - ? ref - .watch(pAmountFormatter(coin)) - .format( - fee, - ) - : "Pending" - : ref - .watch(pAmountFormatter(coin)) - .format( - fee, - ); + child: Builder( + builder: (context) { + String feeString = showFeePending + ? _transaction.isConfirmed( + currentHeight, + minConfirms, + ) + ? ref + .watch(pAmountFormatter(coin)) + .format( + fee, + ) + : "Pending" + : ref + .watch(pAmountFormatter(coin)) + .format( + fee, + ); + + return Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + "Transaction fee", + style: isDesktop + ? STextStyles + .desktopTextExtraExtraSmall( + context, + ) + : STextStyles.itemSubtitle( + context, + ), + ), + if (isDesktop) + const SizedBox( + height: 2, + ), + if (isDesktop) + SelectableText( + feeString, + style: isDesktop + ? STextStyles + .desktopTextExtraExtraSmall( + context, + ).copyWith( + color: Theme.of(context) + .extension< + StackColors>()! + .textDark, + ) + : STextStyles + .itemSubtitle12( + context, + ), + ), + ], + ), + if (!isDesktop) + SelectableText( + feeString, + style: isDesktop + ? STextStyles + .desktopTextExtraExtraSmall( + context, + ).copyWith( + color: Theme.of(context) + .extension< + StackColors>()! + .textDark, + ) + : STextStyles.itemSubtitle12( + context, + ), + ), + if (isDesktop) + IconCopyButton(data: feeString), + ], + ); + }, + ), + ), + isDesktop + ? const _Divider() + : const SizedBox( + height: 12, + ), + RoundedWhiteContainer( + padding: isDesktop + ? const EdgeInsets.all(16) + : const EdgeInsets.all(12), + child: Builder( + builder: (context) { + final String height; + + if (widget.coin is Bitcoincash || + widget.coin is Ecash) { + height = + "${_transaction.height != null && _transaction.height! > 0 ? _transaction.height! : "Pending"}"; + } else { + height = widget.coin is! Epiccash && + _transaction.isConfirmed( + currentHeight, + minConfirms, + ) + ? "${_transaction.height == 0 ? "Unknown" : _transaction.height}" + : _transaction.getConfirmations( + currentHeight, + ) > + 0 + ? "${_transaction.height}" + : "Pending"; + } return Row( mainAxisAlignment: @@ -1230,13 +1405,15 @@ class _TransactionV2DetailsViewState CrossAxisAlignment.start, children: [ Text( - "Transaction fee", + "Block height", style: isDesktop ? STextStyles .desktopTextExtraExtraSmall( - context) + context, + ) : STextStyles.itemSubtitle( - context), + context, + ), ), if (isDesktop) const SizedBox( @@ -1244,133 +1421,45 @@ class _TransactionV2DetailsViewState ), if (isDesktop) SelectableText( - feeString, + height, style: isDesktop ? STextStyles - .desktopTextExtraExtraSmall( - context) - .copyWith( + .desktopTextExtraExtraSmall( + context, + ).copyWith( color: Theme.of(context) .extension< StackColors>()! .textDark, ) : STextStyles.itemSubtitle12( - context), + context, + ), ), ], ), if (!isDesktop) SelectableText( - feeString, + height, style: isDesktop ? STextStyles - .desktopTextExtraExtraSmall( - context) - .copyWith( + .desktopTextExtraExtraSmall( + context, + ).copyWith( color: Theme.of(context) .extension<StackColors>()! .textDark, ) : STextStyles.itemSubtitle12( - context), + context, + ), ), if (isDesktop) - IconCopyButton(data: feeString) + IconCopyButton(data: height), ], ); - }), + }, ), - isDesktop - ? const _Divider() - : const SizedBox( - height: 12, - ), - RoundedWhiteContainer( - padding: isDesktop - ? const EdgeInsets.all(16) - : const EdgeInsets.all(12), - child: Builder(builder: (context) { - final String height; - - if (widget.coin == Coin.bitcoincash || - widget.coin == Coin.eCash || - widget.coin == Coin.bitcoincashTestnet) { - height = - "${_transaction.height != null && _transaction.height! > 0 ? _transaction.height! : "Pending"}"; - } else { - height = widget.coin != Coin.epicCash && - _transaction.isConfirmed( - currentHeight, - minConfirms, - ) - ? "${_transaction.height == 0 ? "Unknown" : _transaction.height}" - : _transaction.getConfirmations( - currentHeight) > - 0 - ? "${_transaction.height}" - : "Pending"; - } - - return Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Text( - "Block height", - style: isDesktop - ? STextStyles - .desktopTextExtraExtraSmall( - context) - : STextStyles.itemSubtitle( - context), - ), - if (isDesktop) - const SizedBox( - height: 2, - ), - if (isDesktop) - SelectableText( - height, - style: isDesktop - ? STextStyles - .desktopTextExtraExtraSmall( - context) - .copyWith( - color: Theme.of(context) - .extension< - StackColors>()! - .textDark, - ) - : STextStyles.itemSubtitle12( - context), - ), - ], - ), - if (!isDesktop) - SelectableText( - height, - style: isDesktop - ? STextStyles - .desktopTextExtraExtraSmall( - context) - .copyWith( - color: Theme.of(context) - .extension<StackColors>()! - .textDark, - ) - : STextStyles.itemSubtitle12( - context), - ), - if (isDesktop) IconCopyButton(data: height), - ], - ); - }), ), if (kDebugMode) @@ -1394,16 +1483,17 @@ class _TransactionV2DetailsViewState style: isDesktop ? STextStyles .desktopTextExtraExtraSmall( - context) + context, + ) : STextStyles.itemSubtitle(context), ), SelectableText( _transaction.subType.toString(), style: isDesktop ? STextStyles - .desktopTextExtraExtraSmall( - context) - .copyWith( + .desktopTextExtraExtraSmall( + context, + ).copyWith( color: Theme.of(context) .extension<StackColors>()! .textDark, @@ -1437,9 +1527,11 @@ class _TransactionV2DetailsViewState style: isDesktop ? STextStyles .desktopTextExtraExtraSmall( - context) + context, + ) : STextStyles.itemSubtitle( - context), + context, + ), ), const SizedBox( height: 8, @@ -1452,21 +1544,22 @@ class _TransactionV2DetailsViewState _transaction.txid, style: isDesktop ? STextStyles - .desktopTextExtraExtraSmall( - context) - .copyWith( + .desktopTextExtraExtraSmall( + context, + ).copyWith( color: Theme.of(context) .extension<StackColors>()! .textDark, ) : STextStyles.itemSubtitle12( - context), + context, + ), ), - if (coin != Coin.epicCash) + if (coin is! Epiccash) const SizedBox( height: 8, ), - if (coin != Coin.epicCash) + if (coin is! Epiccash) CustomTextButton( text: "Open in block explorer", onTap: () async { @@ -1478,12 +1571,14 @@ class _TransactionV2DetailsViewState if (ref .read( - prefsChangeNotifierProvider) + prefsChangeNotifierProvider, + ) .hideBlockExplorerWarning == false) { final shouldContinue = await showExplorerWarning( - "${uri.scheme}://${uri.host}"); + "${uri.scheme}://${uri.host}", + ); if (!shouldContinue) { return; @@ -1544,12 +1639,12 @@ class _TransactionV2DetailsViewState ], ), ), - // if ((coin == Coin.firoTestNet || coin == Coin.firo) && + // if ((coin is FiroTestNet || coin is Firo) && // _transaction.subType == "mint") // const SizedBox( // height: 12, // ), - // if ((coin == Coin.firoTestNet || coin == Coin.firo) && + // if ((coin is FiroTestNet || coin is Firo) && // _transaction.subType == "mint") // RoundedWhiteContainer( // child: Column( @@ -1621,13 +1716,13 @@ class _TransactionV2DetailsViewState // ], // ), // ), - if (coin == Coin.epicCash) + if (coin is Epiccash) isDesktop ? const _Divider() : const SizedBox( height: 12, ), - if (coin == Coin.epicCash) + if (coin is Epiccash) RoundedWhiteContainer( padding: isDesktop ? const EdgeInsets.all(16) @@ -1646,9 +1741,11 @@ class _TransactionV2DetailsViewState style: isDesktop ? STextStyles .desktopTextExtraExtraSmall( - context) + context, + ) : STextStyles.itemSubtitle( - context), + context, + ), ), // Flexible( // child: FittedBox( @@ -1658,15 +1755,16 @@ class _TransactionV2DetailsViewState _transaction.slateId ?? "Unknown", style: isDesktop ? STextStyles - .desktopTextExtraExtraSmall( - context) - .copyWith( + .desktopTextExtraExtraSmall( + context, + ).copyWith( color: Theme.of(context) .extension<StackColors>()! .textDark, ) : STextStyles.itemSubtitle12( - context), + context, + ), ), // ), // ), @@ -1698,7 +1796,7 @@ class _TransactionV2DetailsViewState ), ), floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, - floatingActionButton: (coin == Coin.epicCash && + floatingActionButton: (coin is Epiccash && _transaction.getConfirmations(currentHeight) < 1 && _transaction.isCancelled == false) ? ConditionalParent( @@ -1724,11 +1822,13 @@ class _TransactionV2DetailsViewState if (wallet is EpiccashWallet) { final String? id = _transaction.slateId; if (id == null) { - unawaited(showFloatingFlushBar( - type: FlushBarType.warning, - message: "Could not find Epic transaction ID", - context: context, - )); + unawaited( + showFloatingFlushBar( + type: FlushBarType.warning, + message: "Could not find Epic transaction ID", + context: context, + ), + ); return; } @@ -1773,11 +1873,13 @@ class _TransactionV2DetailsViewState } } } else { - unawaited(showFloatingFlushBar( - type: FlushBarType.warning, - message: "ERROR: Wallet type is not Epic Cash", - context: context, - )); + unawaited( + showFloatingFlushBar( + type: FlushBarType.warning, + message: "ERROR: Wallet type is not Epic Cash", + context: context, + ), + ); return; } }, @@ -1804,7 +1906,7 @@ class OutputCard extends ConsumerWidget { final String address; final Amount amount; - final Coin coin; + final CryptoCurrency coin; @override Widget build(BuildContext context, WidgetRef ref) { @@ -1847,14 +1949,14 @@ class OutputCard extends ConsumerWidget { : STextStyles.itemSubtitle12(context), ), ], - ) + ), ], ); } } class _Divider extends StatelessWidget { - const _Divider({Key? key}) : super(key: key); + const _Divider({super.key}); @override Widget build(BuildContext context) { @@ -1867,9 +1969,9 @@ class _Divider extends StatelessWidget { class IconCopyButton extends StatelessWidget { const IconCopyButton({ - Key? key, + super.key, required this.data, - }) : super(key: key); + }); final String data; @@ -1913,9 +2015,9 @@ class IconCopyButton extends StatelessWidget { class IconPencilButton extends StatelessWidget { const IconPencilButton({ - Key? key, + super.key, this.onPressed, - }) : super(key: key); + }); final VoidCallback? onPressed; diff --git a/lib/pages/wallet_view/transaction_views/tx_v2/transaction_v2_list.dart b/lib/pages/wallet_view/transaction_views/tx_v2/transaction_v2_list.dart index ac868aee9..21c0cbb9e 100644 --- a/lib/pages/wallet_view/transaction_views/tx_v2/transaction_v2_list.dart +++ b/lib/pages/wallet_view/transaction_views/tx_v2/transaction_v2_list.dart @@ -23,8 +23,8 @@ import 'package:stackwallet/providers/db/main_db_provider.dart'; import 'package:stackwallet/providers/global/wallets_provider.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/loading_indicator.dart'; class TransactionsV2List extends ConsumerStatefulWidget { @@ -45,7 +45,7 @@ class _TransactionsV2ListState extends ConsumerState<TransactionsV2List> { late final StreamSubscription<List<TransactionV2>> _subscription; late final Query<TransactionV2> _query; - late final Coin coin; + late final CryptoCurrency coin; BorderRadius get _borderRadiusFirst { return BorderRadius.only( diff --git a/lib/pages/wallet_view/transaction_views/tx_v2/transaction_v2_list_item.dart b/lib/pages/wallet_view/transaction_views/tx_v2/transaction_v2_list_item.dart index ec5c50183..2c18faee1 100644 --- a/lib/pages/wallet_view/transaction_views/tx_v2/transaction_v2_list_item.dart +++ b/lib/pages/wallet_view/transaction_views/tx_v2/transaction_v2_list_item.dart @@ -10,9 +10,9 @@ import 'package:stackwallet/pages/wallet_view/transaction_views/tx_v2/transactio import 'package:stackwallet/providers/global/trades_service_provider.dart'; import 'package:stackwallet/route_generator.dart'; import 'package:stackwallet/themes/stack_colors.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; import 'package:stackwallet/widgets/desktop/desktop_dialog.dart'; import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart'; @@ -29,7 +29,7 @@ class TxListItem extends ConsumerWidget { final Object tx; final BorderRadius? radius; - final Coin coin; + final CryptoCurrency coin; @override Widget build(BuildContext context, WidgetRef ref) { diff --git a/lib/pages/wallet_view/wallet_view.dart b/lib/pages/wallet_view/wallet_view.dart index 8abbd4d16..76c2b5d74 100644 --- a/lib/pages/wallet_view/wallet_view.dart +++ b/lib/pages/wallet_view/wallet_view.dart @@ -60,11 +60,15 @@ import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/backup_frequency_type.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/sync_type_enum.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/show_loading.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/banano.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/bitcoin.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; +import 'package:stackwallet/wallets/crypto_currency/intermediate/frost_currency.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; import 'package:stackwallet/wallets/wallet/impl/bitcoin_frost_wallet.dart'; import 'package:stackwallet/wallets/wallet/impl/firo_wallet.dart'; @@ -120,7 +124,7 @@ class WalletView extends ConsumerStatefulWidget { class _WalletViewState extends ConsumerState<WalletView> { late final EventBus eventBus; late final String walletId; - late final Coin coin; + late final CryptoCurrency coin; late final bool isSparkWallet; @@ -184,8 +188,7 @@ class _WalletViewState extends ConsumerState<WalletView> { isSparkWallet = wallet is SparkInterface; - if (coin == Coin.firo && - (wallet as FiroWallet).lelantusCoinIsarRescanRequired) { + if (coin is Firo && (wallet as FiroWallet).lelantusCoinIsarRescanRequired) { _rescanningOnOpen = true; _lelantusRescanRecovery = true; _firoRescanRecovery(); @@ -384,9 +387,9 @@ class _WalletViewState extends ConsumerState<WalletView> { } Future<void> _onExchangePressed(BuildContext context) async { - final Coin coin = ref.read(pWalletCoin(walletId)); + final CryptoCurrency coin = ref.read(pWalletCoin(walletId)); - if (coin.isTestNet) { + if (coin.network == CryptoCurrencyNetwork.test) { await showDialog<void>( context: context, builder: (_) => const StackOkDialog( @@ -421,7 +424,7 @@ class _WalletViewState extends ConsumerState<WalletView> { WalletInitiatedExchangeView.routeName, arguments: Tuple2( walletId, - currency == null ? Coin.bitcoin : coin, + currency == null ? Bitcoin(CryptoCurrencyNetwork.main) : coin, ), ), ); @@ -430,9 +433,9 @@ class _WalletViewState extends ConsumerState<WalletView> { } Future<void> _onBuyPressed(BuildContext context) async { - final Coin coin = ref.read(pWalletCoin(walletId)); + final CryptoCurrency coin = ref.read(pWalletCoin(walletId)); - if (coin.isTestNet) { + if (coin.network == CryptoCurrencyNetwork.test) { await showDialog<void>( context: context, builder: (_) => const StackOkDialog( @@ -444,7 +447,8 @@ class _WalletViewState extends ConsumerState<WalletView> { unawaited( Navigator.of(context).pushNamed( BuyInWalletView.routeName, - arguments: coin.hasBuySupport ? coin : Coin.bitcoin, + arguments: + coin.hasBuySupport ? coin : Bitcoin(CryptoCurrencyNetwork.main), ), ); } @@ -1020,7 +1024,7 @@ class _WalletViewState extends ConsumerState<WalletView> { } }, ), - if (ref.watch(pWalletCoin(walletId)).isFrost) + if (ref.watch(pWalletCoin(walletId)) is FrostCurrency) WalletNavigationBarItemData( label: "Sign", icon: const FrostSignNavIcon(), @@ -1058,14 +1062,14 @@ class _WalletViewState extends ConsumerState<WalletView> { }, ), if (Constants.enableExchange && - !ref.watch(pWalletCoin(walletId)).isFrost) + ref.watch(pWalletCoin(walletId)) is! FrostCurrency) WalletNavigationBarItemData( label: "Swap", icon: const ExchangeNavIcon(), onTap: () => _onExchangePressed(context), ), if (Constants.enableExchange && - !ref.watch(pWalletCoin(walletId)).isFrost) + ref.watch(pWalletCoin(walletId)) is! FrostCurrency) WalletNavigationBarItemData( label: "Buy", icon: const BuyNavIcon(), @@ -1091,7 +1095,7 @@ class _WalletViewState extends ConsumerState<WalletView> { ); }, ), - if (coin == Coin.banano) + if (coin is Banano) WalletNavigationBarItemData( icon: SvgPicture.asset( Assets.svg.monkey, diff --git a/lib/pages/wallets_view/sub_widgets/favorite_card.dart b/lib/pages/wallets_view/sub_widgets/favorite_card.dart index 4ef59bf0b..008f9c39a 100644 --- a/lib/pages/wallets_view/sub_widgets/favorite_card.dart +++ b/lib/pages/wallets_view/sub_widgets/favorite_card.dart @@ -21,10 +21,10 @@ import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount_formatter.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/show_loading.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/cw_based_interface.dart'; import 'package:stackwallet/widgets/coin_card.dart'; @@ -32,11 +32,11 @@ import 'package:stackwallet/widgets/conditional_parent.dart'; class FavoriteCard extends ConsumerStatefulWidget { const FavoriteCard({ - Key? key, + super.key, required this.walletId, required this.width, required this.height, - }) : super(key: key); + }); final String walletId; final double width; @@ -192,7 +192,7 @@ class _FavoriteCardState extends ConsumerState<FavoriteCard> { ); Amount total = balance.total; - if (coin == Coin.firo || coin == Coin.firoTestNet) { + if (coin is Firo) { total += ref .watch( pWalletBalanceSecondary(walletId), diff --git a/lib/pages/wallets_view/sub_widgets/wallet_list_item.dart b/lib/pages/wallets_view/sub_widgets/wallet_list_item.dart index a708267a9..15d069c5d 100644 --- a/lib/pages/wallets_view/sub_widgets/wallet_list_item.dart +++ b/lib/pages/wallets_view/sub_widgets/wallet_list_item.dart @@ -17,27 +17,27 @@ import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/pages/wallet_view/wallet_view.dart'; import 'package:stackwallet/pages/wallets_view/wallets_overview.dart'; import 'package:stackwallet/providers/providers.dart'; -import 'package:stackwallet/supported_coins.dart'; import 'package:stackwallet/themes/coin_icon_provider.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/show_loading.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/ethereum.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/cw_based_interface.dart'; import 'package:stackwallet/widgets/dialogs/tor_warning_dialog.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; class WalletListItem extends ConsumerWidget { const WalletListItem({ - Key? key, + super.key, required this.coin, required this.walletCount, - }) : super(key: key); + }); - final Coin coin; + final CryptoCurrency coin; final int walletCount; @override @@ -52,7 +52,7 @@ class WalletListItem extends ConsumerWidget { padding: const EdgeInsets.all(0), child: MaterialButton( // splashColor: Theme.of(context).extension<StackColors>()!.highlight, - key: Key("walletListItemButtonKey_${coin.name}"), + key: Key("walletListItemButtonKey_${coin.identifier}"), padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 13), materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, shape: RoundedRectangleBorder( @@ -63,8 +63,7 @@ class WalletListItem extends ConsumerWidget { // Check if Tor is enabled... if (ref.read(prefsChangeNotifierProvider).useTor) { // ... and if the coin supports Tor. - final cryptocurrency = SupportedCoins.getCryptoCurrencyFor(coin); - if (!cryptocurrency.torSupport) { + if (!coin.torSupport) { // If not, show a Tor warning dialog. final shouldContinue = await showDialog<bool>( context: context, @@ -79,7 +78,7 @@ class WalletListItem extends ConsumerWidget { } } - if (walletCount == 1 && coin != Coin.ethereum) { + if (walletCount == 1 && coin is! Ethereum) { final wallet = ref .read(pWallets) .wallets diff --git a/lib/pages/wallets_view/wallets_overview.dart b/lib/pages/wallets_view/wallets_overview.dart index 0f6cef1a6..c70357434 100644 --- a/lib/pages/wallets_view/wallets_overview.dart +++ b/lib/pages/wallets_view/wallets_overview.dart @@ -21,9 +21,10 @@ import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/ethereum.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/isar/models/wallet_info.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; import 'package:stackwallet/wallets/wallet/wallet.dart'; @@ -40,12 +41,12 @@ import 'package:tuple/tuple.dart'; class WalletsOverview extends ConsumerStatefulWidget { const WalletsOverview({ - Key? key, + super.key, required this.coin, this.navigatorState, - }) : super(key: key); + }); - final Coin coin; + final CryptoCurrency coin; final NavigatorState? navigatorState; static const routeName = "/walletsOverview"; @@ -116,7 +117,7 @@ class _EthWalletsOverviewState extends ConsumerState<WalletsOverview> { ref.read(mainDBProvider).isar.walletInfo.where().findAllSync(); walletsData.removeWhere((e) => e.coin != widget.coin); - if (widget.coin == Coin.ethereum) { + if (widget.coin is Ethereum) { for (final data in walletsData) { final List<EthContract> contracts = []; final contractAddresses = diff --git a/lib/pages_desktop_specific/address_book_view/desktop_address_book.dart b/lib/pages_desktop_specific/address_book_view/desktop_address_book.dart index 5932c0826..7546b84fc 100644 --- a/lib/pages_desktop_specific/address_book_view/desktop_address_book.dart +++ b/lib/pages_desktop_specific/address_book_view/desktop_address_book.dart @@ -22,12 +22,14 @@ import 'package:stackwallet/providers/db/main_db_provider.dart'; import 'package:stackwallet/providers/global/address_book_service_provider.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/ui/address_book_providers/address_book_filter_provider.dart'; +import 'package:stackwallet/supported_coins.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/spark_interface.dart'; import 'package:stackwallet/widgets/address_book_card.dart'; import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart'; @@ -97,8 +99,10 @@ class _DesktopAddressBook extends ConsumerState<DesktopAddressBook> { ref.refresh(addressBookFilterProvider); // if (widget.coin == null) { - final List<Coin> coins = Coin.values.toList(); - coins.remove(Coin.firoTestNet); + final coins = SupportedCoins.cryptocurrencies.toList(); + coins.removeWhere( + (e) => e is Firo && e.network == CryptoCurrencyNetwork.test, + ); final bool showTestNet = ref.read(prefsChangeNotifierProvider).showTestNetCoins; @@ -106,9 +110,10 @@ class _DesktopAddressBook extends ConsumerState<DesktopAddressBook> { if (showTestNet) { ref.read(addressBookFilterProvider).addAll(coins, false); } else { - ref - .read(addressBookFilterProvider) - .addAll(coins.where((e) => !e.isTestNet), false); + ref.read(addressBookFilterProvider).addAll( + coins.where((e) => e.network != CryptoCurrencyNetwork.test), + false, + ); } // } else { // ref.read(addressBookFilterProvider).add(widget.coin!, false); @@ -133,7 +138,7 @@ class _DesktopAddressBook extends ConsumerState<DesktopAddressBook> { addresses.add( ContactAddressEntry() - ..coinName = wallet.info.coin.name + ..coinName = wallet.info.coin.identifier ..address = addressString ..label = "Current Receiving" ..other = wallet.info.name, diff --git a/lib/pages_desktop_specific/address_book_view/subwidgets/desktop_address_card.dart b/lib/pages_desktop_specific/address_book_view/subwidgets/desktop_address_card.dart index 13cdc24e4..684c16025 100644 --- a/lib/pages_desktop_specific/address_book_view/subwidgets/desktop_address_card.dart +++ b/lib/pages_desktop_specific/address_book_view/subwidgets/desktop_address_card.dart @@ -22,7 +22,7 @@ import 'package:stackwallet/themes/coin_icon_provider.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; + import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart'; diff --git a/lib/pages_desktop_specific/cashfusion/desktop_cashfusion_view.dart b/lib/pages_desktop_specific/cashfusion/desktop_cashfusion_view.dart index e8aa2436a..7c8a394a3 100644 --- a/lib/pages_desktop_specific/cashfusion/desktop_cashfusion_view.dart +++ b/lib/pages_desktop_specific/cashfusion/desktop_cashfusion_view.dart @@ -25,8 +25,8 @@ import 'package:stackwallet/providers/global/wallets_provider.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/cash_fusion_interface.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; @@ -60,7 +60,7 @@ class _DesktopCashFusion extends ConsumerState<DesktopCashFusionView> { late final FocusNode portFocusNode; late final TextEditingController fusionRoundController; late final FocusNode fusionRoundFocusNode; - late final Coin coin; + late final CryptoCurrency coin; bool _enableStartButton = false; bool _enableSSLCheckbox = false; diff --git a/lib/pages_desktop_specific/cashfusion/sub_widgets/fusion_dialog.dart b/lib/pages_desktop_specific/cashfusion/sub_widgets/fusion_dialog.dart index 6d4225fab..3eb98c0ba 100644 --- a/lib/pages_desktop_specific/cashfusion/sub_widgets/fusion_dialog.dart +++ b/lib/pages_desktop_specific/cashfusion/sub_widgets/fusion_dialog.dart @@ -7,9 +7,9 @@ import 'package:stackwallet/providers/cash_fusion/fusion_progress_ui_state_provi import 'package:stackwallet/providers/global/prefs_provider.dart'; import 'package:stackwallet/providers/global/wallets_provider.dart'; import 'package:stackwallet/themes/stack_colors.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/show_loading.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/cash_fusion_interface.dart'; import 'package:stackwallet/widgets/desktop/desktop_dialog.dart'; @@ -30,9 +30,9 @@ class CashFusionState { class FusionDialogView extends ConsumerStatefulWidget { const FusionDialogView({ - Key? key, + super.key, required this.walletId, - }) : super(key: key); + }); final String walletId; @@ -41,13 +41,13 @@ class FusionDialogView extends ConsumerStatefulWidget { } class _FusionDialogViewState extends ConsumerState<FusionDialogView> { - late final Coin coin; + late final CryptoCurrency coin; Future<bool> _requestAndProcessCancel() async { if (!ref.read(fusionProgressUIStateProvider(widget.walletId)).running) { return true; } else { - bool? shouldCancel = await showDialog<bool?>( + final bool? shouldCancel = await showDialog<bool?>( context: context, barrierDismissible: false, builder: (_) => DesktopDialog( diff --git a/lib/pages_desktop_specific/coin_control/desktop_coin_control_use_dialog.dart b/lib/pages_desktop_specific/coin_control/desktop_coin_control_use_dialog.dart index 3ef549e83..5c46236ae 100644 --- a/lib/pages_desktop_specific/coin_control/desktop_coin_control_use_dialog.dart +++ b/lib/pages_desktop_specific/coin_control/desktop_coin_control_use_dialog.dart @@ -22,8 +22,8 @@ import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; import 'package:stackwallet/widgets/animated_widgets/rotate_icon.dart'; import 'package:stackwallet/widgets/conditional_parent.dart'; @@ -43,10 +43,10 @@ final desktopUseUTXOs = StateProvider((ref) => <UTXO>{}); class DesktopCoinControlUseDialog extends ConsumerStatefulWidget { const DesktopCoinControlUseDialog({ - Key? key, + super.key, required this.walletId, this.amountToSend, - }) : super(key: key); + }); final String walletId; final Amount? amountToSend; @@ -59,7 +59,7 @@ class DesktopCoinControlUseDialog extends ConsumerStatefulWidget { class _DesktopCoinControlUseDialogState extends ConsumerState<DesktopCoinControlUseDialog> { late final TextEditingController _searchController; - late final Coin coin; + late final CryptoCurrency coin; final searchFieldFocusNode = FocusNode(); final Set<UtxoRowData> _selectedUTXOsData = {}; @@ -110,7 +110,7 @@ class _DesktopCoinControlUseDialogState filter: _filter, sort: _sort, searchTerm: _searchString, - coin: coin, + cryptoCurrency: coin, ); } else { _map = null; @@ -119,18 +119,18 @@ class _DesktopCoinControlUseDialogState filter: _filter, sort: _sort, searchTerm: _searchString, - coin: coin, + cryptoCurrency: coin, ); } final Amount selectedSum = _selectedUTXOs.map((e) => e.value).fold( Amount( rawValue: BigInt.zero, - fractionDigits: coin.decimals, + fractionDigits: coin.fractionDigits, ), (value, element) => value += Amount( rawValue: BigInt.from(element), - fractionDigits: coin.decimals, + fractionDigits: coin.fractionDigits, ), ); @@ -486,7 +486,7 @@ class _DesktopCoinControlUseDialogState ), Text( "${widget.amountToSend!.decimal.toStringAsFixed( - coin.decimals, + coin.fractionDigits, )}" " ${coin.ticker}", style: @@ -521,7 +521,7 @@ class _DesktopCoinControlUseDialogState ), Text( "${selectedSum.decimal.toStringAsFixed( - coin.decimals, + coin.fractionDigits, )} ${coin.ticker}", style: STextStyles.desktopTextExtraExtraSmall( context) diff --git a/lib/pages_desktop_specific/coin_control/desktop_coin_control_view.dart b/lib/pages_desktop_specific/coin_control/desktop_coin_control_view.dart index 2b58652a7..e19f6f7d8 100644 --- a/lib/pages_desktop_specific/coin_control/desktop_coin_control_view.dart +++ b/lib/pages_desktop_specific/coin_control/desktop_coin_control_view.dart @@ -22,8 +22,8 @@ import 'package:stackwallet/themes/coin_icon_provider.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; import 'package:stackwallet/widgets/animated_widgets/rotate_icon.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; @@ -55,7 +55,7 @@ class DesktopCoinControlView extends ConsumerStatefulWidget { class _DesktopCoinControlViewState extends ConsumerState<DesktopCoinControlView> { late final TextEditingController _searchController; - late final Coin coin; + late final CryptoCurrency coin; final searchFieldFocusNode = FocusNode(); final Set<UtxoRowData> _selectedUTXOs = {}; @@ -93,7 +93,7 @@ class _DesktopCoinControlViewState filter: _filter, sort: _sort, searchTerm: _searchString, - coin: coin, + cryptoCurrency: coin, ); } else { _map = null; @@ -102,7 +102,7 @@ class _DesktopCoinControlViewState filter: _filter, sort: _sort, searchTerm: _searchString, - coin: coin, + cryptoCurrency: coin, ); } diff --git a/lib/pages_desktop_specific/coin_control/utxo_row.dart b/lib/pages_desktop_specific/coin_control/utxo_row.dart index dbb2d8afe..fcc8aebf7 100644 --- a/lib/pages_desktop_specific/coin_control/utxo_row.dart +++ b/lib/pages_desktop_specific/coin_control/utxo_row.dart @@ -18,7 +18,6 @@ import 'package:stackwallet/providers/global/wallets_provider.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount_formatter.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; import 'package:stackwallet/widgets/conditional_parent.dart'; @@ -158,7 +157,7 @@ class _UtxoRowState extends ConsumerState<UtxoRow> { ref.watch(pAmountFormatter(coin)).format( Amount( rawValue: BigInt.from(utxo.value), - fractionDigits: coin.decimals, + fractionDigits: coin.fractionDigits, ), ), textAlign: TextAlign.right, @@ -180,7 +179,7 @@ class _UtxoRowState extends ConsumerState<UtxoRow> { ref.watch(pAmountFormatter(coin)).format( Amount( rawValue: BigInt.from(utxo.value), - fractionDigits: coin.decimals, + fractionDigits: coin.fractionDigits, ), ), textAlign: TextAlign.right, diff --git a/lib/pages_desktop_specific/desktop_exchange/exchange_steps/step_scaffold.dart b/lib/pages_desktop_specific/desktop_exchange/exchange_steps/step_scaffold.dart index b01cf6898..a5c9fa0db 100644 --- a/lib/pages_desktop_specific/desktop_exchange/exchange_steps/step_scaffold.dart +++ b/lib/pages_desktop_specific/desktop_exchange/exchange_steps/step_scaffold.dart @@ -28,10 +28,10 @@ import 'package:stackwallet/providers/global/trades_service_provider.dart'; import 'package:stackwallet/route_generator.dart'; import 'package:stackwallet/services/exchange/exchange_response.dart'; import 'package:stackwallet/services/notifications_api.dart'; +import 'package:stackwallet/supported_coins.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/exchange_rate_type_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; @@ -51,9 +51,9 @@ final desktopExchangeModelProvider = class StepScaffold extends ConsumerStatefulWidget { const StepScaffold({ - Key? key, + super.key, required this.initialStep, - }) : super(key: key); + }); final int initialStep; @@ -194,9 +194,9 @@ class _StepScaffoldState extends ConsumerState<StepScaffold> { void sendFromStack() { final trade = ref.read(desktopExchangeModelProvider)!.trade!; final address = trade.payInAddress; - final coin = coinFromTickerCaseInsensitive(trade.payInCurrency); + final coin = SupportedCoins.getCryptoCurrencyForTicker(trade.payInCurrency); final amount = Decimal.parse(trade.payInAmount).toAmount( - fractionDigits: coin.decimals, + fractionDigits: coin.fractionDigits, ); showDialog<void>( diff --git a/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_2.dart b/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_2.dart index c3178b809..6f50a7347 100644 --- a/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_2.dart +++ b/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_2.dart @@ -17,10 +17,10 @@ import 'package:stackwallet/pages_desktop_specific/desktop_exchange/subwidgets/d import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/address_book_address_chooser/address_book_address_chooser.dart'; import 'package:stackwallet/providers/exchange/exchange_send_from_wallet_id_provider.dart'; import 'package:stackwallet/providers/global/wallets_provider.dart'; +import 'package:stackwallet/supported_coins.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart'; @@ -59,7 +59,7 @@ class _DesktopStep2State extends ConsumerState<DesktopStep2> { bool isStackCoin(String ticker) { try { - coinFromTickerCaseInsensitive(ticker); + SupportedCoins.getCryptoCurrencyForTicker(ticker); return true; } on ArgumentError catch (_) { return false; @@ -68,7 +68,7 @@ class _DesktopStep2State extends ConsumerState<DesktopStep2> { void selectRecipientAddressFromStack() async { try { - final coin = coinFromTickerCaseInsensitive( + final coin = SupportedCoins.getCryptoCurrencyForTicker( ref.read(desktopExchangeModelProvider)!.receiveTicker, ); @@ -101,7 +101,7 @@ class _DesktopStep2State extends ConsumerState<DesktopStep2> { void selectRefundAddressFromStack() async { try { - final coin = coinFromTickerCaseInsensitive( + final coin = SupportedCoins.getCryptoCurrencyForTicker( ref.read(desktopExchangeModelProvider)!.sendTicker, ); @@ -131,7 +131,7 @@ class _DesktopStep2State extends ConsumerState<DesktopStep2> { } void selectRecipientFromAddressBook() async { - final coin = coinFromTickerCaseInsensitive( + final coin = SupportedCoins.getCryptoCurrencyForTicker( ref.read(desktopExchangeModelProvider)!.receiveTicker, ); @@ -178,7 +178,7 @@ class _DesktopStep2State extends ConsumerState<DesktopStep2> { } void selectRefundFromAddressBook() async { - final coin = coinFromTickerCaseInsensitive( + final coin = SupportedCoins.getCryptoCurrencyForTicker( ref.read(desktopExchangeModelProvider)!.sendTicker, ); diff --git a/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_4.dart b/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_4.dart index 1787f1add..4c579647e 100644 --- a/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_4.dart +++ b/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_4.dart @@ -15,8 +15,8 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/pages_desktop_specific/desktop_exchange/exchange_steps/step_scaffold.dart'; import 'package:stackwallet/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_item.dart'; import 'package:stackwallet/providers/providers.dart'; +import 'package:stackwallet/supported_coins.dart'; import 'package:stackwallet/themes/stack_colors.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/widgets/rounded_container.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; @@ -37,7 +37,7 @@ class _DesktopStep4State extends ConsumerState<DesktopStep4> { bool _isWalletCoinAndHasWallet(String ticker) { try { - final coin = coinFromTickerCaseInsensitive(ticker); + final coin = SupportedCoins.getCryptoCurrencyForTicker(ticker); return ref .read(pWallets) .wallets diff --git a/lib/pages_desktop_specific/desktop_exchange/subwidgets/desktop_choose_from_stack.dart b/lib/pages_desktop_specific/desktop_exchange/subwidgets/desktop_choose_from_stack.dart index f1ffa7fed..a30387f24 100644 --- a/lib/pages_desktop_specific/desktop_exchange/subwidgets/desktop_choose_from_stack.dart +++ b/lib/pages_desktop_specific/desktop_exchange/subwidgets/desktop_choose_from_stack.dart @@ -17,8 +17,9 @@ import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount_formatter.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart'; import 'package:stackwallet/widgets/desktop/secondary_button.dart'; @@ -31,11 +32,11 @@ import 'package:tuple/tuple.dart'; class DesktopChooseFromStack extends ConsumerStatefulWidget { const DesktopChooseFromStack({ - Key? key, + super.key, required this.coin, - }) : super(key: key); + }); - final Coin coin; + final CryptoCurrency coin; @override ConsumerState<DesktopChooseFromStack> createState() => @@ -282,9 +283,9 @@ class _DesktopChooseFromStackState class _BalanceDisplay extends ConsumerWidget { const _BalanceDisplay({ - Key? key, + super.key, required this.walletId, - }) : super(key: key); + }); final String walletId; @@ -292,7 +293,7 @@ class _BalanceDisplay extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final coin = ref.watch(pWalletCoin(walletId)); Amount total = ref.watch(pWalletBalance(walletId)).total; - if (coin == Coin.firo || coin == Coin.firoTestNet) { + if (coin is Firo) { total += ref.watch(pWalletBalanceSecondary(walletId)).total; total += ref.watch(pWalletBalanceTertiary(walletId)).total; } diff --git a/lib/pages_desktop_specific/my_stack_view/coin_wallets_table.dart b/lib/pages_desktop_specific/my_stack_view/coin_wallets_table.dart index 94cdf75f8..8624eca28 100644 --- a/lib/pages_desktop_specific/my_stack_view/coin_wallets_table.dart +++ b/lib/pages_desktop_specific/my_stack_view/coin_wallets_table.dart @@ -15,20 +15,20 @@ import 'package:stackwallet/providers/global/active_wallet_provider.dart'; import 'package:stackwallet/providers/global/wallets_provider.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/show_loading.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/cw_based_interface.dart'; import 'package:stackwallet/widgets/rounded_container.dart'; import 'package:stackwallet/widgets/wallet_info_row/wallet_info_row.dart'; class CoinWalletsTable extends ConsumerWidget { const CoinWalletsTable({ - Key? key, + super.key, required this.coin, - }) : super(key: key); + }); - final Coin coin; + final CryptoCurrency coin; @override Widget build(BuildContext context, WidgetRef ref) { @@ -57,7 +57,7 @@ class CoinWalletsTable extends ConsumerWidget { children: [ for (int i = 0; i < walletIds.length; i++) Column( - key: Key("${coin.name}_$runtimeType${walletIds[i]}_key"), + key: Key("${coin.identifier}_$runtimeType${walletIds[i]}_key"), children: [ if (i != 0) const SizedBox( diff --git a/lib/pages_desktop_specific/my_stack_view/paynym/desktop_paynym_send_dialog.dart b/lib/pages_desktop_specific/my_stack_view/paynym/desktop_paynym_send_dialog.dart index b77135f96..9d9b8b802 100644 --- a/lib/pages_desktop_specific/my_stack_view/paynym/desktop_paynym_send_dialog.dart +++ b/lib/pages_desktop_specific/my_stack_view/paynym/desktop_paynym_send_dialog.dart @@ -25,7 +25,6 @@ import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount_formatter.dart'; import 'package:stackwallet/utilities/barcode_scanner_interface.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; import 'package:stackwallet/widgets/desktop/desktop_dialog.dart'; diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_summary_table.dart b/lib/pages_desktop_specific/my_stack_view/wallet_summary_table.dart index 3b3c6f32f..b7be2c2d4 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_summary_table.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_summary_table.dart @@ -15,12 +15,11 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/pages/wallets_view/wallets_overview.dart'; import 'package:stackwallet/providers/providers.dart'; -import 'package:stackwallet/supported_coins.dart'; import 'package:stackwallet/themes/coin_icon_provider.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/isar/providers/all_wallets_info_provider.dart'; import 'package:stackwallet/widgets/conditional_parent.dart'; import 'package:stackwallet/widgets/desktop/desktop_dialog.dart'; @@ -54,7 +53,7 @@ class _WalletTableState extends ConsumerState<WalletSummaryTable> { child: child, ), child: DesktopWalletSummaryRow( - key: Key("DesktopWalletSummaryRow_key_${coin.name}"), + key: Key("DesktopWalletSummaryRow_key_${coin.identifier}"), coin: coin, walletCount: walletsByCoin[index].wallets.length, ), @@ -75,7 +74,7 @@ class DesktopWalletSummaryRow extends ConsumerStatefulWidget { required this.walletCount, }); - final Coin coin; + final CryptoCurrency coin; final int walletCount; @override @@ -91,8 +90,7 @@ class _DesktopWalletSummaryRowState // Check if Tor is enabled... if (ref.read(prefsChangeNotifierProvider).useTor) { // ... and if the coin supports Tor. - final cryptocurrency = SupportedCoins.getCryptoCurrencyFor(widget.coin); - if (!cryptocurrency.torSupport) { + if (!widget.coin.torSupport) { // If not, show a Tor warning dialog. final shouldContinue = await showDialog<bool>( context: context, @@ -222,7 +220,7 @@ class _DesktopWalletSummaryRowState class TablePriceInfo extends ConsumerWidget { const TablePriceInfo({Key? key, required this.coin}) : super(key: key); - final Coin coin; + final CryptoCurrency coin; @override Widget build(BuildContext context, WidgetRef ref) { diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/address_book_address_chooser/address_book_address_chooser.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/address_book_address_chooser/address_book_address_chooser.dart index ee10acb54..9f220ddca 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/address_book_address_chooser/address_book_address_chooser.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/address_book_address_chooser/address_book_address_chooser.dart @@ -17,20 +17,20 @@ import 'package:stackwallet/providers/global/address_book_service_provider.dart' import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/icon_widgets/x_icon.dart'; import 'package:stackwallet/widgets/stack_text_field.dart'; import 'package:stackwallet/widgets/textfield_icon_button.dart'; class AddressBookAddressChooser extends StatefulWidget { const AddressBookAddressChooser({ - Key? key, + super.key, this.coin, - }) : super(key: key); + }); - final Coin? coin; + final CryptoCurrency? coin; @override State<AddressBookAddressChooser> createState() => @@ -92,7 +92,7 @@ class _AddressBookAddressChooserState extends State<AddressBookAddressChooser> { } for (int i = 0; i < contact.addresses.length; i++) { if (contact.addresses[i].label.toLowerCase().contains(text) || - contact.addresses[i].coin.name.toLowerCase().contains(text) || + contact.addresses[i].coin.identifier.toLowerCase().contains(text) || contact.addresses[i].coin.prettyName.toLowerCase().contains(text) || contact.addresses[i].coin.ticker.toLowerCase().contains(text) || contact.addresses[i].address.toLowerCase().contains(text)) { diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/address_book_address_chooser/sub_widgets/contact_list_item.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/address_book_address_chooser/sub_widgets/contact_list_item.dart index 7d0be498e..5c6856a1f 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/address_book_address_chooser/sub_widgets/contact_list_item.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/address_book_address_chooser/sub_widgets/contact_list_item.dart @@ -12,8 +12,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/providers/global/address_book_service_provider.dart'; import 'package:stackwallet/themes/stack_colors.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/address_book_card.dart'; import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart'; import 'package:stackwallet/widgets/expandable.dart'; @@ -22,13 +22,13 @@ import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_ class ContactListItem extends ConsumerStatefulWidget { const ContactListItem({ - Key? key, + super.key, required this.contactId, this.filterByCoin, - }) : super(key: key); + }); final String contactId; - final Coin? filterByCoin; + final CryptoCurrency? filterByCoin; @override ConsumerState<ContactListItem> createState() => _ContactListItemState(); @@ -36,7 +36,7 @@ class ContactListItem extends ConsumerStatefulWidget { class _ContactListItemState extends ConsumerState<ContactListItem> { late final String contactId; - late final Coin? filterByCoin; + late final CryptoCurrency? filterByCoin; ExpandableState _state = ExpandableState.collapsed; diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_auth_send.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_auth_send.dart index aba28300b..561781cf6 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_auth_send.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_auth_send.dart @@ -17,8 +17,8 @@ import 'package:stackwallet/providers/desktop/storage_crypto_handler_provider.da import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/desktop/primary_button.dart'; import 'package:stackwallet/widgets/desktop/secondary_button.dart'; import 'package:stackwallet/widgets/loading_indicator.dart'; @@ -30,7 +30,7 @@ class DesktopAuthSend extends ConsumerStatefulWidget { required this.coin, }); - final Coin coin; + final CryptoCurrency coin; @override ConsumerState<DesktopAuthSend> createState() => _DesktopAuthSendState(); diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_fee_dropdown.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_fee_dropdown.dart index 255d64c63..f32f36a23 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_fee_dropdown.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_fee_dropdown.dart @@ -23,9 +23,13 @@ import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount_formatter.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/ethereum.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/monero.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/wownero.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/isar/providers/eth/current_token_wallet_provider.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; import 'package:stackwallet/wallets/wallet/impl/firo_wallet.dart'; @@ -38,10 +42,10 @@ final tokenFeeSessionCacheProvider = class DesktopFeeDropDown extends ConsumerStatefulWidget { const DesktopFeeDropDown({ - Key? key, + super.key, required this.walletId, this.isToken = false, - }) : super(key: key); + }); final String walletId; final bool isToken; @@ -67,7 +71,7 @@ class _DesktopFeeDropDownState extends ConsumerState<DesktopFeeDropDown> { required Amount amount, required FeeRateType feeRateType, required int feeRate, - required Coin coin, + required CryptoCurrency coin, }) async { switch (feeRateType) { case FeeRateType.fast: @@ -80,11 +84,11 @@ class _DesktopFeeDropDownState extends ConsumerState<DesktopFeeDropDown> { if (widget.isToken == false) { final wallet = ref.read(pWallets).getWallet(walletId); - if (coin == Coin.monero || coin == Coin.wownero) { + if (coin is Monero || coin is Wownero) { final fee = await wallet.estimateFeeFor( amount, MoneroTransactionPriority.fast.raw!); ref.read(feeSheetSessionCacheProvider).fast[amount] = fee; - } else if (coin == Coin.firo || coin == Coin.firoTestNet) { + } else if (coin is Firo) { final Amount fee; switch (ref.read(publicPrivateBalanceStateProvider.state).state) { case FiroType.spark: @@ -124,11 +128,11 @@ class _DesktopFeeDropDownState extends ConsumerState<DesktopFeeDropDown> { if (widget.isToken == false) { final wallet = ref.read(pWallets).getWallet(walletId); - if (coin == Coin.monero || coin == Coin.wownero) { + if (coin is Monero || coin is Wownero) { final fee = await wallet.estimateFeeFor( amount, MoneroTransactionPriority.regular.raw!); ref.read(feeSheetSessionCacheProvider).average[amount] = fee; - } else if (coin == Coin.firo || coin == Coin.firoTestNet) { + } else if (coin is Firo) { final Amount fee; switch (ref.read(publicPrivateBalanceStateProvider.state).state) { case FiroType.spark: @@ -168,11 +172,11 @@ class _DesktopFeeDropDownState extends ConsumerState<DesktopFeeDropDown> { if (widget.isToken == false) { final wallet = ref.read(pWallets).getWallet(walletId); - if (coin == Coin.monero || coin == Coin.wownero) { + if (coin is Monero || coin is Wownero) { final fee = await wallet.estimateFeeFor( amount, MoneroTransactionPriority.slow.raw!); ref.read(feeSheetSessionCacheProvider).slow[amount] = fee; - } else if (coin == Coin.firo || coin == Coin.firoTestNet) { + } else if (coin is Firo) { final Amount fee; switch (ref.read(publicPrivateBalanceStateProvider.state).state) { case FiroType.spark: @@ -306,7 +310,7 @@ class FeeDropDownChild extends ConsumerWidget { required Amount amount, required FeeRateType feeRateType, required int feeRate, - required Coin coin, + required CryptoCurrency coin, }) feeFor; final bool isSelected; @@ -390,10 +394,10 @@ class FeeDropDownChild extends ConsumerWidget { ), if (feeObject != null) Text( - coin == Coin.ethereum + coin is Ethereum ? "" : estimatedTimeToBeIncludedInNextBlock( - Constants.targetBlockTimeInSeconds(coin), + coin.targetBlockTimeSeconds, feeRateType == FeeRateType.fast ? feeObject!.numberOfBlocksFast : feeRateType == FeeRateType.slow diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_receive.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_receive.dart index 6250dfd8e..3f69ccaaf 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_receive.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_receive.dart @@ -28,9 +28,9 @@ import 'package:stackwallet/utilities/address_utils.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/isar/providers/eth/current_token_wallet_provider.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/multi_address_interface.dart'; @@ -45,11 +45,11 @@ import 'package:tuple/tuple.dart'; class DesktopReceive extends ConsumerStatefulWidget { const DesktopReceive({ - Key? key, + super.key, required this.walletId, this.contractAddress, this.clipboard = const ClipboardWrapper(), - }) : super(key: key); + }); final String walletId; final String? contractAddress; @@ -60,7 +60,7 @@ class DesktopReceive extends ConsumerStatefulWidget { } class _DesktopReceiveState extends ConsumerState<DesktopReceive> { - late final Coin coin; + late final CryptoCurrency coin; late final String walletId; late final ClipboardInterface clipboard; late final bool supportsSpark; diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_send.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_send.dart index 2614a58d4..d7ed9ceca 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_send.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_send.dart @@ -41,13 +41,20 @@ import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/barcode_scanner_interface.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/prefs.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/epiccash.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/ethereum.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/monero.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/stellar.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/tezos.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/wownero.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; +import 'package:stackwallet/wallets/crypto_currency/intermediate/nano_currency.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; import 'package:stackwallet/wallets/models/tx_data.dart'; import 'package:stackwallet/wallets/wallet/impl/firo_wallet.dart'; @@ -73,13 +80,13 @@ import 'package:stackwallet/widgets/textfield_icon_button.dart'; class DesktopSend extends ConsumerStatefulWidget { const DesktopSend({ - Key? key, + super.key, required this.walletId, this.autoFillData, this.clipboard = const ClipboardWrapper(), this.barcodeScanner = const BarcodeScannerWrapper(), this.accountLite, - }) : super(key: key); + }); final String walletId; final SendViewAutoFillData? autoFillData; @@ -93,7 +100,7 @@ class DesktopSend extends ConsumerStatefulWidget { class _DesktopSendState extends ConsumerState<DesktopSend> { late final String walletId; - late final Coin coin; + late final CryptoCurrency coin; late final ClipboardInterface clipboard; late final BarcodeScannerInterface scanner; @@ -141,7 +148,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> { final Amount amount = ref.read(pSendAmount)!; final Amount availableBalance; - if ((coin == Coin.firo || coin == Coin.firoTestNet)) { + if ((coin is Firo)) { switch (ref.read(publicPrivateBalanceStateProvider.state).state) { case FiroType.public: availableBalance = wallet.info.cachedBalance.spendable; @@ -447,7 +454,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> { txData = txData.copyWith( note: _note ?? "", ); - if (coin == Coin.epicCash) { + if (coin is Epiccash) { txData = txData.copyWith( noteOnChain: _onChainNote ?? "", ); @@ -658,7 +665,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> { // autofill amount field if (results["amount"] != null) { final amount = Decimal.parse(results["amount"]!).toAmount( - fractionDigits: coin.decimals, + fractionDigits: coin.fractionDigits, ); cryptoAmountController.text = ref .read(pAmountFormatter(coin)) @@ -721,7 +728,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> { content = content.substring(0, content.indexOf("\n")); } - if (coin == Coin.epicCash) { + if (coin is Epiccash) { // strip http:// and https:// if content contains @ content = formatAddress(content); } @@ -764,13 +771,13 @@ class _DesktopSendState extends ConsumerState<DesktopSend> { ref.read(priceAnd24hChangeNotifierProvider).getPrice(coin).item1; if (_price == Decimal.zero) { - amount = Decimal.zero.toAmount(fractionDigits: coin.decimals); + amount = Decimal.zero.toAmount(fractionDigits: coin.fractionDigits); } else { amount = baseAmount <= Amount.zero - ? Decimal.zero.toAmount(fractionDigits: coin.decimals) + ? Decimal.zero.toAmount(fractionDigits: coin.fractionDigits) : (baseAmount.decimal / _price) - .toDecimal(scaleOnInfinitePrecision: coin.decimals) - .toAmount(fractionDigits: coin.decimals); + .toDecimal(scaleOnInfinitePrecision: coin.fractionDigits) + .toAmount(fractionDigits: coin.fractionDigits); } if (_cachedAmountToSend != null && _cachedAmountToSend == amount) { return; @@ -788,7 +795,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> { cryptoAmountController.text = amountString; _cryptoAmountChangeLock = false; } else { - amount = Decimal.zero.toAmount(fractionDigits: coin.decimals); + amount = Decimal.zero.toAmount(fractionDigits: coin.fractionDigits); _cryptoAmountChangeLock = true; cryptoAmountController.text = ""; _cryptoAmountChangeLock = false; @@ -804,26 +811,26 @@ class _DesktopSendState extends ConsumerState<DesktopSend> { Future<void> sendAllTapped() async { final info = ref.read(pWalletInfo(walletId)); - if (coin == Coin.firo || coin == Coin.firoTestNet) { + if (coin is Firo) { switch (ref.read(publicPrivateBalanceStateProvider.state).state) { case FiroType.public: cryptoAmountController.text = info.cachedBalance.spendable.decimal - .toStringAsFixed(coin.decimals); + .toStringAsFixed(coin.fractionDigits); break; case FiroType.lelantus: cryptoAmountController.text = info .cachedBalanceSecondary.spendable.decimal - .toStringAsFixed(coin.decimals); + .toStringAsFixed(coin.fractionDigits); break; case FiroType.spark: cryptoAmountController.text = info .cachedBalanceTertiary.spendable.decimal - .toStringAsFixed(coin.decimals); + .toStringAsFixed(coin.fractionDigits); break; } } else { - cryptoAmountController.text = - info.cachedBalance.spendable.decimal.toStringAsFixed(coin.decimals); + cryptoAmountController.text = info.cachedBalance.spendable.decimal + .toStringAsFixed(coin.fractionDigits); } } @@ -852,7 +859,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> { coin = ref.read(pWalletInfo(walletId)).coin; clipboard = widget.clipboard; scanner = widget.barcodeScanner; - isStellar = coin == Coin.stellar || coin == Coin.stellarTestnet; + isStellar = coin is Stellar; sendToController = TextEditingController(); cryptoAmountController = TextEditingController(); @@ -927,7 +934,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> { ); // add listener for epic cash to strip http:// and https:// prefixes if the address also ocntains an @ symbol (indicating an epicbox address) - if (coin == Coin.epicCash) { + if (coin is Epiccash) { sendToController.addListener(() { _address = sendToController.text; @@ -955,7 +962,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> { const SizedBox( height: 4, ), - if (coin == Coin.firo || coin == Coin.firoTestNet) + if (coin is Firo) Text( "Send from", style: STextStyles.desktopTextExtraSmall(context).copyWith( @@ -965,11 +972,11 @@ class _DesktopSendState extends ConsumerState<DesktopSend> { ), textAlign: TextAlign.left, ), - if (coin == Coin.firo || coin == Coin.firoTestNet) + if (coin is Firo) const SizedBox( height: 10, ), - if (coin == Coin.firo || coin == Coin.firoTestNet) + if (coin is Firo) DropdownButtonHideUnderline( child: DropdownButton2( isExpanded: true, @@ -1076,7 +1083,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> { ), ), ), - if (coin == Coin.firo || coin == Coin.firoTestNet) + if (coin is Firo) const SizedBox( height: 20, ), @@ -1122,7 +1129,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> { ), textAlign: TextAlign.left, ), - if (coin != Coin.ethereum && coin != Coin.tezos) + if (coin is! Ethereum && coin is! Tezos) CustomTextButton( text: "Send all ${coin.ticker}", onTap: sendAllTapped, @@ -1150,7 +1157,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> { textAlign: TextAlign.right, inputFormatters: [ AmountInputFormatter( - decimals: coin.decimals, + decimals: coin.fractionDigits, unit: ref.watch(pAmountUnit(coin)), locale: locale, ), @@ -1455,13 +1462,13 @@ class _DesktopSendState extends ConsumerState<DesktopSend> { if (_address == null || _address!.isEmpty) { error = null; - } else if (coin == Coin.firo || coin == Coin.firoTestNet) { + } else if (coin is Firo) { if (ref.watch(publicPrivateBalanceStateProvider) == FiroType.lelantus) { if (_data != null && _data!.contactLabel == _address) { error = SparkInterface.validateSparkAddress( address: _data!.address, - isTestNet: coin.isTestNet, + isTestNet: coin.network == CryptoCurrencyNetwork.test, ) ? "Lelantus to Spark not supported" : null; @@ -1532,8 +1539,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> { Constants.size.circularBorderRadius, ), child: TextField( - maxLength: - (coin == Coin.firo || coin == Coin.firoTestNet) ? 31 : null, + maxLength: (coin is Firo) ? 31 : null, minLines: 1, maxLines: 5, key: const Key("sendViewMemoFieldKey"), @@ -1590,12 +1596,11 @@ class _DesktopSendState extends ConsumerState<DesktopSend> { const SizedBox( height: 20, ), - if (!([Coin.nano, Coin.banano, Coin.epicCash, Coin.tezos] - .contains(coin))) + if (coin is! NanoCurrency && coin is! Epiccash && coin is! Tezos) ConditionalParent( condition: ref.watch(pWallets).getWallet(walletId) is ElectrumXInterface && - !(((coin == Coin.firo || coin == Coin.firoTestNet) && + !(((coin is Firo) && (ref.watch(publicPrivateBalanceStateProvider.state).state == FiroType.lelantus || ref @@ -1638,7 +1643,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> { ), child: Text( "Transaction fee" - "${isCustomFee ? "" : " (${coin == Coin.ethereum ? "max" : "estimated"})"}", + "${isCustomFee ? "" : " (${coin is Ethereum ? "max" : "estimated"})"}", style: STextStyles.desktopTextExtraSmall(context).copyWith( color: Theme.of(context) .extension<StackColors>()! @@ -1647,13 +1652,11 @@ class _DesktopSendState extends ConsumerState<DesktopSend> { textAlign: TextAlign.left, ), ), - if (!([Coin.nano, Coin.banano, Coin.epicCash, Coin.tezos] - .contains(coin))) + if (coin is! NanoCurrency && coin is! Epiccash && coin is! Tezos) const SizedBox( height: 10, ), - if (!([Coin.nano, Coin.banano, Coin.epicCash, Coin.tezos] - .contains(coin))) + if (coin is! NanoCurrency && coin is! Epiccash && coin is! Tezos) if (!isCustomFee) Padding( padding: const EdgeInsets.all(10), @@ -1676,7 +1679,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> { required Amount amount, required FeeRateType feeRateType, required int feeRate, - required Coin coin, + required CryptoCurrency coin, }) async { if (ref .read(feeSheetSessionCacheProvider) @@ -1685,8 +1688,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> { final wallet = ref.read(pWallets).getWallet(walletId); - if (coin == Coin.monero || - coin == Coin.wownero) { + if (coin is Monero || coin is Wownero) { final fee = await wallet.estimateFeeFor( amount, MoneroTransactionPriority.regular.raw!, @@ -1694,8 +1696,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> { ref .read(feeSheetSessionCacheProvider) .average[amount] = fee; - } else if ((coin == Coin.firo || - coin == Coin.firoTestNet) && + } else if ((coin is Firo) && ref .read( publicPrivateBalanceStateProvider @@ -1764,7 +1765,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> { } }, ) - : (coin == Coin.firo || coin == Coin.firoTestNet) && + : (coin is Firo) && ref .watch( publicPrivateBalanceStateProvider.state, @@ -1775,7 +1776,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> { "~${ref.watch(pAmountFormatter(coin)).format( Amount( rawValue: BigInt.parse("3794"), - fractionDigits: coin.decimals, + fractionDigits: coin.fractionDigits, ), indicatePrecisionLoss: false, )}", diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_token_send.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_token_send.dart index eef67e694..b93850b0b 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_token_send.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_token_send.dart @@ -33,11 +33,12 @@ import 'package:stackwallet/utilities/amount/amount_input_formatter.dart'; import 'package:stackwallet/utilities/barcode_scanner_interface.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/prefs.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/isar/providers/eth/current_token_wallet_provider.dart'; import 'package:stackwallet/wallets/isar/providers/eth/token_balance_provider.dart'; import 'package:stackwallet/wallets/models/tx_data.dart'; @@ -76,7 +77,7 @@ class DesktopTokenSend extends ConsumerStatefulWidget { class _DesktopTokenSendState extends ConsumerState<DesktopTokenSend> { late final String walletId; - late final Coin coin; + late final CryptoCurrency coin; late final ClipboardInterface clipboard; late final BarcodeScannerInterface scanner; @@ -224,7 +225,7 @@ class _DesktopTokenSendState extends ConsumerState<DesktopTokenSend> { child: Padding( padding: const EdgeInsets.all(32), child: BuildingTransactionDialog( - coin: tokenWallet.cryptoCurrency.coin, + coin: tokenWallet.cryptoCurrency, isSpark: false, onCancel: () { wasCancelled = true; @@ -719,7 +720,7 @@ class _DesktopTokenSendState extends ConsumerState<DesktopTokenSend> { const SizedBox( height: 4, ), - if (coin == Coin.firo) + if (coin is Firo) Text( "Send from", style: STextStyles.desktopTextExtraSmall(context).copyWith( diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_wallet_features.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_wallet_features.dart index d655879e8..3cef858d3 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_wallet_features.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_wallet_features.dart @@ -34,9 +34,10 @@ import 'package:stackwallet/themes/theme_providers.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/banano.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; import 'package:stackwallet/wallets/wallet/impl/firo_wallet.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/cash_fusion_interface.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/coin_control_interface.dart'; @@ -50,9 +51,9 @@ import 'package:stackwallet/widgets/loading_indicator.dart'; class DesktopWalletFeatures extends ConsumerStatefulWidget { const DesktopWalletFeatures({ - Key? key, + super.key, required this.walletId, - }) : super(key: key); + }); final String walletId; @@ -357,10 +358,9 @@ class _DesktopWalletFeaturesState extends ConsumerState<DesktopWalletFeatures> { (value) => value.enableCoinControl, ), )) || - coin == Coin.firo || - coin == Coin.firoTestNet || + coin is Firo || // manager.hasWhirlpoolSupport || - coin == Coin.banano || + coin is Banano || wallet is OrdinalsInterface || wallet is CashFusionInterface; diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_wallet_summary.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_wallet_summary.dart index 77a5f0f5f..a52ee3d71 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_wallet_summary.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_wallet_summary.dart @@ -20,9 +20,9 @@ import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_ import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount_formatter.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/wallet_balance_toggle_state.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; import 'package:stackwallet/wallets/isar/providers/eth/current_token_wallet_provider.dart'; import 'package:stackwallet/wallets/isar/providers/eth/token_balance_provider.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; @@ -63,7 +63,7 @@ class _WDesktopWalletSummaryState extends ConsumerState<DesktopWalletSummary> { ), ); final coin = ref.watch(pWalletCoin(widget.walletId)); - final isFiro = coin == Coin.firo || coin == Coin.firoTestNet; + final isFiro = coin is Firo; final locale = ref.watch( localeServiceChangeNotifierProvider.select((value) => value.locale)); @@ -154,12 +154,11 @@ class _WDesktopWalletSummaryState extends ConsumerState<DesktopWalletSummary> { ? ref.watch(pCurrentTokenWallet)!.tokenContract.address : null, ), - if (coin == Coin.firo || coin == Coin.firoTestNet) + if (coin is Firo) const SizedBox( width: 8, ), - if (coin == Coin.firo || coin == Coin.firoTestNet) - const DesktopPrivateBalanceToggleButton(), + if (coin is Firo) const DesktopPrivateBalanceToggleButton(), const SizedBox( width: 8, ), diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/more_features/more_features_dialog.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/more_features/more_features_dialog.dart index 1eaccd885..70ce9e32b 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/more_features/more_features_dialog.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/more_features/more_features_dialog.dart @@ -15,8 +15,9 @@ import 'package:stackwallet/providers/global/prefs_provider.dart'; import 'package:stackwallet/providers/global/wallets_provider.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/banano.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/cash_fusion_interface.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/coin_control_interface.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/ordinals_interface.dart'; @@ -85,8 +86,7 @@ class _MoreFeaturesDialogState extends ConsumerState<MoreFeaturesDialog> { const DesktopDialogCloseButton(), ], ), - if (wallet.info.coin == Coin.firo || - wallet.info.coin == Coin.firoTestNet) + if (wallet.info.coin is Firo) _MoreFeaturesItem( label: "Anonymize funds", detail: "Anonymize funds", @@ -122,7 +122,7 @@ class _MoreFeaturesDialogState extends ConsumerState<MoreFeaturesDialog> { iconAsset: Assets.svg.ordinal, onPressed: () => widget.onOrdinalsPressed?.call(), ), - if (wallet.info.coin == Coin.banano) + if (wallet.info.coin is Banano) _MoreFeaturesItem( label: "MonKey", detail: "Generate Banano MonKey", @@ -147,12 +147,12 @@ class _MoreFeaturesDialogState extends ConsumerState<MoreFeaturesDialog> { class _MoreFeaturesItem extends StatelessWidget { const _MoreFeaturesItem({ - Key? key, + super.key, required this.label, required this.detail, required this.iconAsset, this.onPressed, - }) : super(key: key); + }); static const double iconSizeBG = 46; static const double iconSize = 24; @@ -209,7 +209,7 @@ class _MoreFeaturesItem extends StatelessWidget { style: STextStyles.desktopTextExtraExtraSmall(context), ), ], - ) + ), ], ), ), diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/my_wallet.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/my_wallet.dart index 63974518b..e7596dd2d 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/my_wallet.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/my_wallet.dart @@ -18,7 +18,8 @@ import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_send.dart'; import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_token_send.dart'; import 'package:stackwallet/providers/global/wallets_provider.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/ethereum.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/wallet/impl/bitcoin_frost_wallet.dart'; import 'package:stackwallet/widgets/custom_tab_view.dart'; import 'package:stackwallet/widgets/desktop/secondary_button.dart'; @@ -46,7 +47,7 @@ class _MyWalletState extends ConsumerState<MyWallet> { ]; late final bool isEth; - late final Coin coin; + late final CryptoCurrency coin; late final bool isFrost; @override @@ -54,7 +55,7 @@ class _MyWalletState extends ConsumerState<MyWallet> { final wallet = ref.read(pWallets).getWallet(widget.walletId); coin = wallet.info.coin; isFrost = wallet is BitcoinFrostWallet; - isEth = coin == Coin.ethereum; + isEth = coin is Ethereum; if (isEth && widget.contractAddress == null) { titles.add("Transactions"); diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/wallet_options_button.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/wallet_options_button.dart index c27b7855d..916201c8f 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/wallet_options_button.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/wallet_options_button.dart @@ -25,8 +25,10 @@ import 'package:stackwallet/route_generator.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; +import 'package:stackwallet/wallets/crypto_currency/intermediate/frost_currency.dart'; +import 'package:stackwallet/wallets/crypto_currency/intermediate/nano_currency.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; enum _WalletOptions { @@ -60,9 +62,9 @@ enum _WalletOptions { class WalletOptionsButton extends StatelessWidget { const WalletOptionsButton({ - Key? key, + super.key, required this.walletId, - }) : super(key: key); + }); final String walletId; @@ -250,7 +252,7 @@ class WalletOptionsButton extends StatelessWidget { class WalletOptionsPopupMenu extends ConsumerWidget { const WalletOptionsPopupMenu({ - Key? key, + super.key, required this.onDeletePressed, required this.onAddressListPressed, required this.onShowXpubPressed, @@ -259,7 +261,7 @@ class WalletOptionsPopupMenu extends ConsumerWidget { required this.onFiroShowSparkCoins, required this.onFrostMSWalletOptionsPressed, required this.walletId, - }) : super(key: key); + }); final VoidCallback onDeletePressed; final VoidCallback onAddressListPressed; @@ -274,17 +276,15 @@ class WalletOptionsPopupMenu extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final coin = ref.watch(pWalletCoin(walletId)); - final firoDebug = - kDebugMode && (coin == Coin.firo || coin == Coin.firoTestNet); + final firoDebug = kDebugMode && (coin is Firo); // TODO: [prio=low] // final bool xpubEnabled = manager.hasXPub; final bool xpubEnabled = false; - final bool canChangeRep = coin == Coin.nano || coin == Coin.banano; + final bool canChangeRep = coin is NanoCurrency; - final bool isFrost = - coin == Coin.bitcoinFrost || coin == Coin.bitcoinFrostTestNet; + final bool isFrost = coin is FrostCurrency; return Stack( children: [ diff --git a/lib/pages_desktop_specific/ordinals/desktop_ordinal_details_view.dart b/lib/pages_desktop_specific/ordinals/desktop_ordinal_details_view.dart index b258d0a5e..b4a4af07f 100644 --- a/lib/pages_desktop_specific/ordinals/desktop_ordinal_details_view.dart +++ b/lib/pages_desktop_specific/ordinals/desktop_ordinal_details_view.dart @@ -18,7 +18,6 @@ import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount_formatter.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/prefs.dart'; import 'package:stackwallet/utilities/show_loading.dart'; import 'package:stackwallet/utilities/text_styles.dart'; @@ -298,7 +297,7 @@ class _DesktopOrdinalDetailsViewState : ref.watch(pAmountFormatter(coin)).format( Amount( rawValue: BigInt.from(utxo!.value), - fractionDigits: coin.decimals, + fractionDigits: coin.fractionDigits, ), ), ); diff --git a/lib/pages_desktop_specific/settings/settings_menu/advanced_settings/desktop_manage_block_explorers_dialog.dart b/lib/pages_desktop_specific/settings/settings_menu/advanced_settings/desktop_manage_block_explorers_dialog.dart index 2fd6431c1..0d4d88328 100644 --- a/lib/pages_desktop_specific/settings/settings_menu/advanced_settings/desktop_manage_block_explorers_dialog.dart +++ b/lib/pages_desktop_specific/settings/settings_menu/advanced_settings/desktop_manage_block_explorers_dialog.dart @@ -14,13 +14,14 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/providers/global/prefs_provider.dart'; +import 'package:stackwallet/supported_coins.dart'; import 'package:stackwallet/themes/coin_icon_provider.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/block_explorers.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/desktop/desktop_dialog.dart'; import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart'; import 'package:stackwallet/widgets/desktop/primary_button.dart'; @@ -29,18 +30,22 @@ import 'package:stackwallet/widgets/rounded_white_container.dart'; class DesktopManageBlockExplorersDialog extends ConsumerWidget { const DesktopManageBlockExplorersDialog({ - Key? key, - }) : super(key: key); + super.key, + }); @override Widget build(BuildContext context, WidgetRef ref) { - bool showTestNet = ref.watch( + final bool showTestNet = ref.watch( prefsChangeNotifierProvider.select((value) => value.showTestNetCoins), ); - final List<Coin> coins = showTestNet - ? Coin.values - : Coin.values.where((e) => !e.isTestNet).toList(); + final coins = showTestNet + ? SupportedCoins.cryptocurrencies + : SupportedCoins.cryptocurrencies + .where( + (e) => e.network == CryptoCurrencyNetwork.main, + ) + .toList(); return DesktopDialog( maxHeight: 850, @@ -139,7 +144,7 @@ class _DesktopEditBlockExplorerDialog extends ConsumerStatefulWidget { const _DesktopEditBlockExplorerDialog({Key? key, required this.coin}) : super(key: key); - final Coin coin; + final CryptoCurrency coin; @override ConsumerState<_DesktopEditBlockExplorerDialog> createState() => diff --git a/lib/pages_desktop_specific/settings/settings_menu/nodes_settings.dart b/lib/pages_desktop_specific/settings/settings_menu/nodes_settings.dart index eec6e1a5f..53cc15f37 100644 --- a/lib/pages_desktop_specific/settings/settings_menu/nodes_settings.dart +++ b/lib/pages_desktop_specific/settings/settings_menu/nodes_settings.dart @@ -16,13 +16,17 @@ import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/manage_nodes_views/coin_nodes_view.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/route_generator.dart'; +import 'package:stackwallet/supported_coins.dart'; import 'package:stackwallet/themes/coin_icon_provider.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/monero.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/wownero.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/icon_widgets/x_icon.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:stackwallet/widgets/stack_text_field.dart'; @@ -38,7 +42,7 @@ class NodesSettings extends ConsumerStatefulWidget { } class _NodesSettings extends ConsumerState<NodesSettings> { - List<Coin> _coins = [...Coin.values]; + List<CryptoCurrency> _coins = [...SupportedCoins.cryptocurrencies]; late final TextEditingController searchNodeController; late final FocusNode searchNodeFocusNode; @@ -47,14 +51,14 @@ class _NodesSettings extends ConsumerState<NodesSettings> { String filter = ""; - List<Coin> _search(String filter, List<Coin> coins) { + List<CryptoCurrency> _search(String filter, List<CryptoCurrency> coins) { if (filter.isEmpty) { return coins; } return coins .where((coin) => coin.prettyName.contains(filter) || - coin.name.contains(filter) || + coin.identifier.contains(filter) || coin.ticker.toLowerCase().contains(filter.toLowerCase())) .toList(); } @@ -64,12 +68,15 @@ class _NodesSettings extends ConsumerState<NodesSettings> { @override void initState() { _coins = _coins.toList(); - _coins.remove(Coin.firoTestNet); + _coins.removeWhere( + (e) => e is Firo && e.network == CryptoCurrencyNetwork.test, + ); if (Platform.isWindows) { - _coins.remove(Coin.monero); - _coins.remove(Coin.wownero); + _coins.removeWhere( + (e) => e is Monero && e is Wownero, + ); } else if (Platform.isLinux) { - _coins.remove(Coin.wownero); + _coins.removeWhere((e) => e is Wownero); } searchNodeController = TextEditingController(); @@ -93,12 +100,17 @@ class _NodesSettings extends ConsumerState<NodesSettings> { Widget build(BuildContext context) { debugPrint("BUILD: $runtimeType"); - bool showTestNet = ref.watch( + final bool showTestNet = ref.watch( prefsChangeNotifierProvider.select((value) => value.showTestNetCoins), ); - List<Coin> coins = - showTestNet ? _coins : _coins.where((e) => !e.isTestNet).toList(); + List<CryptoCurrency> coins = showTestNet + ? _coins + : _coins + .where( + (e) => e.network == CryptoCurrencyNetwork.main, + ) + .toList(); coins = _search(filter, coins); diff --git a/lib/providers/exchange/exchange_form_state_provider.dart b/lib/providers/exchange/exchange_form_state_provider.dart index b4a923b78..b8ad1c2f9 100644 --- a/lib/providers/exchange/exchange_form_state_provider.dart +++ b/lib/providers/exchange/exchange_form_state_provider.dart @@ -18,8 +18,10 @@ import 'package:stackwallet/services/exchange/exchange.dart'; import 'package:stackwallet/services/exchange/exchange_response.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount_unit.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; + import 'package:stackwallet/utilities/enums/exchange_rate_type_enum.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/nano.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:tuple/tuple.dart'; final efEstimatesListProvider = StateProvider.family< @@ -56,8 +58,9 @@ final efSendAmountStringProvider = StateProvider<String>((ref) { string = AmountUnit.normal.displayAmount( amount: amount, locale: locale, - coin: Coin - .nano, // use nano just to ensure decimal.scale < Coin.value.decimals + coin: Nano( + CryptoCurrencyNetwork.main, + ), // use nano just to ensure decimal.scale < Coin.value.decimals withUnitName: false, maxDecimalPlaces: decimal.scale, ); @@ -81,8 +84,9 @@ final efReceiveAmountStringProvider = StateProvider<String>((ref) { string = AmountUnit.normal.displayAmount( amount: amount, locale: locale, - coin: Coin - .nano, // use nano just to ensure decimal.scale < Coin.value.decimals + coin: Nano( + CryptoCurrencyNetwork.main, + ), // use nano just to ensure decimal.scale < Coin.value.decimals withUnitName: false, maxDecimalPlaces: decimal.scale, ); diff --git a/lib/providers/exchange/exchange_send_from_wallet_id_provider.dart b/lib/providers/exchange/exchange_send_from_wallet_id_provider.dart index b2fbec990..3a1c4c452 100644 --- a/lib/providers/exchange/exchange_send_from_wallet_id_provider.dart +++ b/lib/providers/exchange/exchange_send_from_wallet_id_provider.dart @@ -9,8 +9,8 @@ */ import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:tuple/tuple.dart'; final exchangeSendFromWalletIdStateProvider = - StateProvider<Tuple2<String, Coin>?>((ref) => null); + StateProvider<Tuple2<String, CryptoCurrency>?>((ref) => null); diff --git a/lib/providers/ui/preview_tx_button_state_provider.dart b/lib/providers/ui/preview_tx_button_state_provider.dart index 768edf301..0c3b1061f 100644 --- a/lib/providers/ui/preview_tx_button_state_provider.dart +++ b/lib/providers/ui/preview_tx_button_state_provider.dart @@ -11,18 +11,18 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/providers/wallet/public_private_balance_state_provider.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; final pSendAmount = StateProvider.autoDispose<Amount?>((_) => null); final pValidSendToAddress = StateProvider.autoDispose<bool>((_) => false); final pValidSparkSendToAddress = StateProvider.autoDispose<bool>((_) => false); final pPreviewTxButtonEnabled = - Provider.autoDispose.family<bool, Coin>((ref, coin) { + Provider.autoDispose.family<bool, CryptoCurrency>((ref, coin) { final amount = ref.watch(pSendAmount) ?? Amount.zero; - // TODO [prio=low]: move away from Coin - if (coin == Coin.firo || coin == Coin.firoTestNet) { + if (coin is Firo) { if (ref.watch(publicPrivateBalanceStateProvider) == FiroType.lelantus) { return ref.watch(pValidSendToAddress) && !ref.watch(pValidSparkSendToAddress) && diff --git a/lib/route_generator.dart b/lib/route_generator.dart index 62bae2bbd..1e32c9969 100644 --- a/lib/route_generator.dart +++ b/lib/route_generator.dart @@ -188,7 +188,7 @@ import 'package:stackwallet/services/event_bus/events/global/node_connection_sta import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_changed_event.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/enums/add_wallet_type_enum.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/crypto_currency/intermediate/frost_currency.dart'; import 'package:stackwallet/wallets/models/tx_data.dart'; import 'package:stackwallet/wallets/wallet/wallet.dart'; @@ -211,21 +211,24 @@ class RouteGenerator { switch (settings.name) { case IntroView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const IntroView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const IntroView(), + settings: RouteSettings(name: settings.name), + ); case DeleteAccountView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const DeleteAccountView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const DeleteAccountView(), + settings: RouteSettings(name: settings.name), + ); case HomeView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const HomeView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const HomeView(), + settings: RouteSettings(name: settings.name), + ); case CreatePinView.routeName: if (args is bool) { @@ -240,9 +243,10 @@ class RouteGenerator { ); } return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const CreatePinView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const CreatePinView(), + settings: RouteSettings(name: settings.name), + ); case StackPrivacyCalls.routeName: if (args is bool) { @@ -253,9 +257,10 @@ class RouteGenerator { ); } return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const StackPrivacyCalls(isSettings: false), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const StackPrivacyCalls(isSettings: false), + settings: RouteSettings(name: settings.name), + ); case ChooseCoinView.routeName: if (args is Tuple3<String, String, String>) { @@ -274,7 +279,7 @@ class RouteGenerator { return _routeError("${settings.name} invalid args: ${args.toString()}"); case ManageExplorerView.routeName: - if (args is Coin) { + if (args is CryptoCurrency) { return getRoute( shouldUseMaterialRoute: useMaterialPageRoute, builder: (_) => ManageExplorerView( @@ -303,15 +308,17 @@ class RouteGenerator { case WalletsView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const WalletsView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const WalletsView(), + settings: RouteSettings(name: settings.name), + ); case AddWalletView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const AddWalletView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const AddWalletView(), + settings: RouteSettings(name: settings.name), + ); case EditWalletTokensView.routeName: if (args is String) { @@ -376,7 +383,7 @@ class RouteGenerator { ); case WalletsOverview.routeName: - if (args is Coin) { + if (args is CryptoCurrency) { return getRoute( shouldUseMaterialRoute: useMaterialPageRoute, builder: (_) => WalletsOverview( @@ -556,7 +563,7 @@ class RouteGenerator { case FrostSendView.routeName: if (args is ({ String walletId, - Coin coin, + CryptoCurrency coin, })) { return getRoute( shouldUseMaterialRoute: useMaterialPageRoute, @@ -675,9 +682,10 @@ class RouteGenerator { case OrdinalsFilterView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const OrdinalsFilterView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const OrdinalsFilterView(), + settings: RouteSettings(name: settings.name), + ); case UtxoDetailsView.routeName: if (args is Tuple2<Id, String>) { @@ -780,12 +788,13 @@ class RouteGenerator { case GlobalSettingsView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const GlobalSettingsView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const GlobalSettingsView(), + settings: RouteSettings(name: settings.name), + ); case AddressBookView.routeName: - if (args is Coin) { + if (args is CryptoCurrency) { return getRoute( shouldUseMaterialRoute: useMaterialPageRoute, builder: (_) => AddressBookView( @@ -797,87 +806,101 @@ class RouteGenerator { ); } return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const AddressBookView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const AddressBookView(), + settings: RouteSettings(name: settings.name), + ); case AddressBookFilterView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const AddressBookFilterView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const AddressBookFilterView(), + settings: RouteSettings(name: settings.name), + ); case StackBackupView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const StackBackupView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const StackBackupView(), + settings: RouteSettings(name: settings.name), + ); case AutoBackupView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const AutoBackupView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const AutoBackupView(), + settings: RouteSettings(name: settings.name), + ); case EditAutoBackupView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const EditAutoBackupView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const EditAutoBackupView(), + settings: RouteSettings(name: settings.name), + ); case CreateAutoBackupView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const CreateAutoBackupView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const CreateAutoBackupView(), + settings: RouteSettings(name: settings.name), + ); case SecurityView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const SecurityView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const SecurityView(), + settings: RouteSettings(name: settings.name), + ); case ChangePinView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const ChangePinView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const ChangePinView(), + settings: RouteSettings(name: settings.name), + ); case BaseCurrencySettingsView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const BaseCurrencySettingsView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const BaseCurrencySettingsView(), + settings: RouteSettings(name: settings.name), + ); case LanguageSettingsView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const LanguageSettingsView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const LanguageSettingsView(), + settings: RouteSettings(name: settings.name), + ); case TorSettingsView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const TorSettingsView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const TorSettingsView(), + settings: RouteSettings(name: settings.name), + ); case TorSettings.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const TorSettings(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const TorSettings(), + settings: RouteSettings(name: settings.name), + ); case AboutView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const AboutView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const AboutView(), + settings: RouteSettings(name: settings.name), + ); case DebugView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const DebugView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const DebugView(), + settings: RouteSettings(name: settings.name), + ); case XPubView.routeName: if (args is String) { @@ -909,69 +932,80 @@ class RouteGenerator { case AppearanceSettingsView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const AppearanceSettingsView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const AppearanceSettingsView(), + settings: RouteSettings(name: settings.name), + ); case SyncingPreferencesView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const SyncingPreferencesView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const SyncingPreferencesView(), + settings: RouteSettings(name: settings.name), + ); case StartupPreferencesView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const StartupPreferencesView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const StartupPreferencesView(), + settings: RouteSettings(name: settings.name), + ); case StartupWalletSelectionView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const StartupWalletSelectionView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const StartupWalletSelectionView(), + settings: RouteSettings(name: settings.name), + ); case ManageNodesView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const ManageNodesView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const ManageNodesView(), + settings: RouteSettings(name: settings.name), + ); case SyncingOptionsView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const SyncingOptionsView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const SyncingOptionsView(), + settings: RouteSettings(name: settings.name), + ); case WalletSyncingOptionsView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const WalletSyncingOptionsView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const WalletSyncingOptionsView(), + settings: RouteSettings(name: settings.name), + ); case AdvancedSettingsView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const AdvancedSettingsView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const AdvancedSettingsView(), + settings: RouteSettings(name: settings.name), + ); case SupportView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const SupportView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const SupportView(), + settings: RouteSettings(name: settings.name), + ); case AddAddressBookEntryView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const AddAddressBookEntryView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const AddAddressBookEntryView(), + settings: RouteSettings(name: settings.name), + ); case RestoreFromFileView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const RestoreFromFileView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const RestoreFromFileView(), + settings: RouteSettings(name: settings.name), + ); case RestoreFromEncryptedStringView.routeName: if (args is String) { @@ -989,12 +1023,13 @@ class RouteGenerator { case ManageCoinUnitsView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const ManageCoinUnitsView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const ManageCoinUnitsView(), + settings: RouteSettings(name: settings.name), + ); case EditCoinUnitsView.routeName: - if (args is Coin) { + if (args is CryptoCurrency) { return getRoute( shouldUseMaterialRoute: useMaterialPageRoute, builder: (_) => EditCoinUnitsView( @@ -1009,24 +1044,27 @@ class RouteGenerator { case CreateBackupInfoView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const CreateBackupInfoView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const CreateBackupInfoView(), + settings: RouteSettings(name: settings.name), + ); case CreateBackupView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const CreateBackupView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const CreateBackupView(), + settings: RouteSettings(name: settings.name), + ); case HiddenSettings.routeName: return getRoute( - shouldUseMaterialRoute: false, - builder: (_) => const HiddenSettings(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: false, + builder: (_) => const HiddenSettings(), + settings: RouteSettings(name: settings.name), + ); case CoinNodesView.routeName: - if (args is Coin) { + if (args is CryptoCurrency) { return getRoute( shouldUseMaterialRoute: useMaterialPageRoute, builder: (_) => CoinNodesView( @@ -1040,7 +1078,7 @@ class RouteGenerator { return _routeError("${settings.name} invalid args: ${args.toString()}"); case NodeDetailsView.routeName: - if (args is Tuple3<Coin, String, String>) { + if (args is Tuple3<CryptoCurrency, String, String>) { return getRoute( shouldUseMaterialRoute: useMaterialPageRoute, builder: (_) => NodeDetailsView( @@ -1100,7 +1138,8 @@ class RouteGenerator { return _routeError("${settings.name} invalid args: ${args.toString()}"); case AddEditNodeView.routeName: - if (args is Tuple4<AddEditNodeViewType, Coin, String?, String>) { + if (args + is Tuple4<AddEditNodeViewType, CryptoCurrency, String?, String>) { return getRoute( shouldUseMaterialRoute: useMaterialPageRoute, builder: (_) => AddEditNodeView( @@ -1291,7 +1330,7 @@ class RouteGenerator { return _routeError("${settings.name} invalid args: ${args.toString()}"); case NameYourWalletView.routeName: - if (args is Tuple2<AddWalletType, Coin>) { + if (args is Tuple2<AddWalletType, CryptoCurrency>) { return getRoute( shouldUseMaterialRoute: useMaterialPageRoute, builder: (_) => NameYourWalletView( @@ -1306,7 +1345,7 @@ class RouteGenerator { return _routeError("${settings.name} invalid args: ${args.toString()}"); case NewWalletRecoveryPhraseWarningView.routeName: - if (args is Tuple2<String, Coin>) { + if (args is Tuple2<String, CryptoCurrency>) { return getRoute( shouldUseMaterialRoute: useMaterialPageRoute, builder: (_) => NewWalletRecoveryPhraseWarningView( @@ -1321,7 +1360,7 @@ class RouteGenerator { return _routeError("${settings.name} invalid args: ${args.toString()}"); case RestoreOptionsView.routeName: - if (args is Tuple2<String, Coin>) { + if (args is Tuple2<String, CryptoCurrency>) { return getRoute( shouldUseMaterialRoute: useMaterialPageRoute, builder: (_) => RestoreOptionsView( @@ -1336,7 +1375,7 @@ class RouteGenerator { return _routeError("${settings.name} invalid args: ${args.toString()}"); case NewWalletOptionsView.routeName: - if (args is Tuple2<String, Coin>) { + if (args is Tuple2<String, CryptoCurrency>) { return getRoute( shouldUseMaterialRoute: useMaterialPageRoute, builder: (_) => NewWalletOptionsView( @@ -1351,15 +1390,16 @@ class RouteGenerator { return _routeError("${settings.name} invalid args: ${args.toString()}"); case RestoreWalletView.routeName: - if (args is Tuple5<String, Coin, int, DateTime, String>) { + if (args is Tuple5<String, CryptoCurrency, int, DateTime, String>) { return getRoute( shouldUseMaterialRoute: useMaterialPageRoute, builder: (_) => RestoreWalletView( - walletName: args.item1, - coin: args.item2, - seedWordsLength: args.item3, - restoreFromDate: args.item4, - mnemonicPassphrase: args.item5), + walletName: args.item1, + coin: args.item2, + seedWordsLength: args.item3, + restoreFromDate: args.item4, + mnemonicPassphrase: args.item5, + ), settings: RouteSettings( name: settings.name, ), @@ -1399,8 +1439,9 @@ class RouteGenerator { case ManageFavoritesView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const ManageFavoritesView()); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const ManageFavoritesView(), + ); case WalletView.routeName: if (args is String) { @@ -1417,7 +1458,7 @@ class RouteGenerator { return _routeError("${settings.name} invalid args: ${args.toString()}"); case TransactionDetailsView.routeName: - if (args is Tuple3<Transaction, Coin, String>) { + if (args is Tuple3<Transaction, CryptoCurrency, String>) { return getRoute( shouldUseMaterialRoute: useMaterialPageRoute, builder: (_) => TransactionDetailsView( @@ -1433,7 +1474,11 @@ class RouteGenerator { return _routeError("${settings.name} invalid args: ${args.toString()}"); case TransactionV2DetailsView.routeName: - if (args is ({TransactionV2 tx, Coin coin, String walletId})) { + if (args is ({ + TransactionV2 tx, + CryptoCurrency coin, + String walletId + })) { return getRoute( shouldUseMaterialRoute: useMaterialPageRoute, builder: (_) => TransactionV2DetailsView( @@ -1451,7 +1496,7 @@ class RouteGenerator { case FusionGroupDetailsView.routeName: if (args is ({ List<TransactionV2> transactions, - Coin coin, + CryptoCurrency coin, String walletId })) { return getRoute( @@ -1509,7 +1554,7 @@ class RouteGenerator { return _routeError("${settings.name} invalid args: ${args.toString()}"); case TransactionSearchFilterView.routeName: - if (args is Coin) { + if (args is CryptoCurrency) { return getRoute( shouldUseMaterialRoute: useMaterialPageRoute, builder: (_) => TransactionSearchFilterView( @@ -1577,7 +1622,7 @@ class RouteGenerator { return _routeError("${settings.name} invalid args: ${args.toString()}"); case SendView.routeName: - if (args is Tuple2<String, Coin>) { + if (args is Tuple2<String, CryptoCurrency>) { return getRoute( shouldUseMaterialRoute: useMaterialPageRoute, builder: (_) => SendView( @@ -1588,7 +1633,8 @@ class RouteGenerator { name: settings.name, ), ); - } else if (args is Tuple3<String, Coin, SendViewAutoFillData>) { + } else if (args + is Tuple3<String, CryptoCurrency, SendViewAutoFillData>) { return getRoute( shouldUseMaterialRoute: useMaterialPageRoute, builder: (_) => SendView( @@ -1600,7 +1646,7 @@ class RouteGenerator { name: settings.name, ), ); - } else if (args is Tuple3<String, Coin, PaynymAccountLite>) { + } else if (args is Tuple3<String, CryptoCurrency, PaynymAccountLite>) { return getRoute( shouldUseMaterialRoute: useMaterialPageRoute, builder: (_) => SendView( @@ -1612,7 +1658,7 @@ class RouteGenerator { name: settings.name, ), ); - } else if (args is ({Coin coin, String walletId})) { + } else if (args is ({CryptoCurrency coin, String walletId})) { return getRoute( shouldUseMaterialRoute: useMaterialPageRoute, builder: (_) => SendView( @@ -1628,7 +1674,7 @@ class RouteGenerator { return _routeError("${settings.name} invalid args: ${args.toString()}"); case TokenSendView.routeName: - if (args is Tuple3<String, Coin, EthContract>) { + if (args is Tuple3<String, CryptoCurrency, EthContract>) { return getRoute( shouldUseMaterialRoute: useMaterialPageRoute, builder: (_) => TokenSendView( @@ -1660,7 +1706,7 @@ class RouteGenerator { return _routeError("${settings.name} invalid args: ${args.toString()}"); case WalletInitiatedExchangeView.routeName: - if (args is Tuple2<String, Coin>) { + if (args is Tuple2<String, CryptoCurrency>) { return getRoute( shouldUseMaterialRoute: useMaterialPageRoute, builder: (_) => Stack( @@ -1679,7 +1725,7 @@ class RouteGenerator { ), ); } - if (args is Tuple3<String, Coin, EthContract?>) { + if (args is Tuple3<String, CryptoCurrency, EthContract?>) { return getRoute( shouldUseMaterialRoute: useMaterialPageRoute, builder: (_) => Stack( @@ -1716,8 +1762,8 @@ class RouteGenerator { return _routeError("${settings.name} invalid args: ${args.toString()}"); case WalletSettingsView.routeName: - if (args - is Tuple4<String, Coin, WalletSyncStatus, NodeConnectionStatus>) { + if (args is Tuple4<String, CryptoCurrency, WalletSyncStatus, + NodeConnectionStatus>) { return getRoute( shouldUseMaterialRoute: useMaterialPageRoute, builder: (_) => WalletSettingsView( @@ -1845,7 +1891,7 @@ class RouteGenerator { return _routeError("${settings.name} invalid args: ${args.toString()}"); case ChooseFromStackView.routeName: - if (args is Coin) { + if (args is CryptoCurrency) { return getRoute( shouldUseMaterialRoute: useMaterialPageRoute, builder: (_) => ChooseFromStackView( @@ -1859,7 +1905,7 @@ class RouteGenerator { return _routeError("${settings.name} invalid args: ${args.toString()}"); case SendFromView.routeName: - if (args is Tuple4<Coin, Amount, String, Trade>) { + if (args is Tuple4<CryptoCurrency, Amount, String, Trade>) { return getRoute( shouldUseMaterialRoute: useMaterialPageRoute, builder: (_) => SendFromView( @@ -1876,7 +1922,7 @@ class RouteGenerator { return _routeError("${settings.name} invalid args: ${args.toString()}"); case GenerateUriQrCodeView.routeName: - if (args is Tuple2<Coin, String>) { + if (args is Tuple2<CryptoCurrency, String>) { return getRoute( shouldUseMaterialRoute: useMaterialPageRoute, builder: (_) => GenerateUriQrCodeView( @@ -1918,21 +1964,24 @@ class RouteGenerator { ); } return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const CreatePasswordView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const CreatePasswordView(), + settings: RouteSettings(name: settings.name), + ); case ForgotPasswordDesktopView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const ForgotPasswordDesktopView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const ForgotPasswordDesktopView(), + settings: RouteSettings(name: settings.name), + ); case ForgottenPassphraseRestoreFromSWB.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const ForgottenPassphraseRestoreFromSWB(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const ForgottenPassphraseRestoreFromSWB(), + settings: RouteSettings(name: settings.name), + ); case DeletePasswordWarningView.routeName: if (args is bool) { @@ -1950,30 +1999,34 @@ class RouteGenerator { case DesktopHomeView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const DesktopHomeView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const DesktopHomeView(), + settings: RouteSettings(name: settings.name), + ); case DesktopNotificationsView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const DesktopNotificationsView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const DesktopNotificationsView(), + settings: RouteSettings(name: settings.name), + ); case DesktopExchangeView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const DesktopExchangeView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const DesktopExchangeView(), + settings: RouteSettings(name: settings.name), + ); case BuyView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const BuyView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const BuyView(), + settings: RouteSettings(name: settings.name), + ); case BuyInWalletView.routeName: - if (args is Coin) { + if (args is CryptoCurrency) { return getRoute( shouldUseMaterialRoute: useMaterialPageRoute, builder: (_) => BuyInWalletView(coin: args), @@ -1982,7 +2035,7 @@ class RouteGenerator { ), ); } - if (args is Tuple2<Coin, EthContract?>) { + if (args is Tuple2<CryptoCurrency, EthContract?>) { return getRoute( shouldUseMaterialRoute: useMaterialPageRoute, builder: (_) => BuyInWalletView( @@ -1998,27 +2051,31 @@ class RouteGenerator { case DesktopBuyView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const DesktopBuyView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const DesktopBuyView(), + settings: RouteSettings(name: settings.name), + ); case DesktopAllTradesView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const DesktopAllTradesView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const DesktopAllTradesView(), + settings: RouteSettings(name: settings.name), + ); case DesktopSettingsView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const DesktopSettingsView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const DesktopSettingsView(), + settings: RouteSettings(name: settings.name), + ); case MyStackView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const MyStackView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const MyStackView(), + settings: RouteSettings(name: settings.name), + ); case DesktopWalletView.routeName: if (args is String) { @@ -2092,75 +2149,87 @@ class RouteGenerator { case BackupRestoreSettings.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const BackupRestoreSettings(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const BackupRestoreSettings(), + settings: RouteSettings(name: settings.name), + ); case SecuritySettings.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const SecuritySettings(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const SecuritySettings(), + settings: RouteSettings(name: settings.name), + ); case CurrencySettings.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const CurrencySettings(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const CurrencySettings(), + settings: RouteSettings(name: settings.name), + ); case LanguageOptionSettings.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const LanguageOptionSettings(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const LanguageOptionSettings(), + settings: RouteSettings(name: settings.name), + ); case NodesSettings.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const NodesSettings(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const NodesSettings(), + settings: RouteSettings(name: settings.name), + ); case SyncingPreferencesSettings.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const SyncingPreferencesSettings(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const SyncingPreferencesSettings(), + settings: RouteSettings(name: settings.name), + ); case AppearanceOptionSettings.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const AppearanceOptionSettings(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const AppearanceOptionSettings(), + settings: RouteSettings(name: settings.name), + ); case ManageThemesView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const ManageThemesView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const ManageThemesView(), + settings: RouteSettings(name: settings.name), + ); case AdvancedSettings.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const AdvancedSettings(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const AdvancedSettings(), + settings: RouteSettings(name: settings.name), + ); case DesktopSupportView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const DesktopSupportView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const DesktopSupportView(), + settings: RouteSettings(name: settings.name), + ); case DesktopAboutView.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const DesktopAboutView(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const DesktopAboutView(), + settings: RouteSettings(name: settings.name), + ); case DesktopAddressBook.routeName: return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const DesktopAddressBook(), - settings: RouteSettings(name: settings.name)); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const DesktopAddressBook(), + settings: RouteSettings(name: settings.name), + ); case WalletKeysDesktopPopup.routeName: if (args is ({ @@ -2413,13 +2482,15 @@ class RouteGenerator { ), body: Center( child: Text( - 'Error handling route, this is not supposed to happen. Try restarting the app.\n$message'), + 'Error handling route, this is not supposed to happen. Try restarting the app.\n$message', + ), ), ); return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => errorView); + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => errorView, + ); } } diff --git a/lib/services/address_book_service.dart b/lib/services/address_book_service.dart index d925a3b0d..43bbc2ff7 100644 --- a/lib/services/address_book_service.dart +++ b/lib/services/address_book_service.dart @@ -12,11 +12,10 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:stackwallet/db/isar/main_db.dart'; import 'package:stackwallet/models/isar/models/contact_entry.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; class AddressBookService extends ChangeNotifier { ContactEntry getContactById(String id) { - ContactEntry? contactEntry = MainDB.instance.getContactEntry(id: id); + final ContactEntry? contactEntry = MainDB.instance.getContactEntry(id: id); if (contactEntry == null) { throw Exception('Contact ID "$id" not found!'); } else { @@ -30,7 +29,7 @@ class AddressBookService extends ChangeNotifier { //TODO search using isar queries Future<List<ContactEntry>> search(String text) async { if (text.isEmpty) return contacts; - var results = contacts.toList(); + final results = contacts.toList(); results.retainWhere((contact) => matches(text, contact)); @@ -47,7 +46,7 @@ class AddressBookService extends ChangeNotifier { } for (int i = 0; i < contact.addresses.length; i++) { if (contact.addresses[i].label.toLowerCase().contains(text) || - contact.addresses[i].coin.name.toLowerCase().contains(text) || + contact.addresses[i].coin.identifier.toLowerCase().contains(text) || contact.addresses[i].coin.prettyName.toLowerCase().contains(text) || contact.addresses[i].coin.ticker.toLowerCase().contains(text) || contact.addresses[i].address.toLowerCase().contains(text)) { diff --git a/lib/services/buy/simplex/simplex_api.dart b/lib/services/buy/simplex/simplex_api.dart index 6ab2736e4..e0e00dd5d 100644 --- a/lib/services/buy/simplex/simplex_api.dart +++ b/lib/services/buy/simplex/simplex_api.dart @@ -19,7 +19,7 @@ import 'package:stackwallet/models/buy/response_objects/quote.dart'; import 'package:stackwallet/networking/http.dart'; import 'package:stackwallet/services/buy/buy_response.dart'; import 'package:stackwallet/services/tor_service.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/supported_coins.dart'; import 'package:stackwallet/utilities/enums/fiat_enum.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/prefs.dart'; @@ -47,30 +47,34 @@ class SimplexAPI { Future<BuyResponse<List<Crypto>>> getSupportedCryptos() async { try { - Map<String, String> headers = { + final Map<String, String> headers = { 'Content-Type': 'application/x-www-form-urlencoded', }; - Map<String, String> data = { + final Map<String, String> data = { 'ROUTE': 'supported_cryptos', }; - Uri url = _buildUri('api.php', data); + final Uri url = _buildUri('api.php', data); - var res = await client.post( + final res = await client.post( url: url, headers: headers, - proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.getProxyInfo() : null, + proxyInfo: Prefs.instance.useTor + ? TorService.sharedInstance.getProxyInfo() + : null, ); if (res.code != 200) { throw Exception( - 'getAvailableCurrencies exception: statusCode= ${res.code}'); + 'getAvailableCurrencies exception: statusCode= ${res.code}', + ); } final jsonArray = jsonDecode(res.body); // TODO handle if invalid json return _parseSupportedCryptos(jsonArray); } catch (e, s) { - Logging.instance.log("getAvailableCurrencies exception: $e\n$s", - level: LogLevel.Error); + Logging.instance.log( + "getAvailableCurrencies exception: $e\n$s", + level: LogLevel.Error, + ); return BuyResponse( exception: BuyException( e.toString(), @@ -82,19 +86,20 @@ class SimplexAPI { BuyResponse<List<Crypto>> _parseSupportedCryptos(dynamic jsonArray) { try { - List<Crypto> cryptos = []; - List<Fiat> fiats = []; + final List<Crypto> cryptos = []; for (final crypto in jsonArray as List) { // TODO validate jsonArray if (isStackCoin("${crypto['ticker_symbol']}")) { - cryptos.add(Crypto.fromJson({ - 'ticker': "${crypto['ticker_symbol']}", - 'name': crypto['name'], - 'network': "${crypto['network']}", - 'contractAddress': "${crypto['contractAddress']}", - 'image': "", - })); + cryptos.add( + Crypto.fromJson({ + 'ticker': "${crypto['ticker_symbol']}", + 'name': crypto['name'], + 'network': "${crypto['network']}", + 'contractAddress': "${crypto['contractAddress']}", + 'image': "", + }), + ); } } @@ -113,30 +118,34 @@ class SimplexAPI { Future<BuyResponse<List<Fiat>>> getSupportedFiats() async { try { - Map<String, String> headers = { + final Map<String, String> headers = { 'Content-Type': 'application/x-www-form-urlencoded', }; - Map<String, String> data = { + final Map<String, String> data = { 'ROUTE': 'supported_fiats', }; - Uri url = _buildUri('api.php', data); + final Uri url = _buildUri('api.php', data); - var res = await client.post( + final res = await client.post( url: url, headers: headers, - proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.getProxyInfo() : null, + proxyInfo: Prefs.instance.useTor + ? TorService.sharedInstance.getProxyInfo() + : null, ); if (res.code != 200) { throw Exception( - 'getAvailableCurrencies exception: statusCode= ${res.code}'); + 'getAvailableCurrencies exception: statusCode= ${res.code}', + ); } final jsonArray = jsonDecode(res.body); // TODO validate json return _parseSupportedFiats(jsonArray); } catch (e, s) { - Logging.instance.log("getAvailableCurrencies exception: $e\n$s", - level: LogLevel.Error); + Logging.instance.log( + "getAvailableCurrencies exception: $e\n$s", + level: LogLevel.Error, + ); return BuyResponse( exception: BuyException( e.toString(), @@ -148,20 +157,22 @@ class SimplexAPI { BuyResponse<List<Fiat>> _parseSupportedFiats(dynamic jsonArray) { try { - List<Crypto> cryptos = []; - List<Fiat> fiats = []; + final List<Crypto> cryptos = []; + final List<Fiat> fiats = []; for (final fiat in jsonArray as List) { if (isSimplexFiat("${fiat['ticker_symbol']}")) { // TODO validate list - fiats.add(Fiat.fromJson({ - 'ticker': "${fiat['ticker_symbol']}", - 'name': fiatFromTickerCaseInsensitive("${fiat['ticker_symbol']}") - .prettyName, - 'minAmount': "${fiat['min_amount']}", - 'maxAmount': "${fiat['max_amount']}", - 'image': "", - })); + fiats.add( + Fiat.fromJson({ + 'ticker': "${fiat['ticker_symbol']}", + 'name': fiatFromTickerCaseInsensitive("${fiat['ticker_symbol']}") + .prettyName, + 'minAmount': "${fiat['min_amount']}", + 'maxAmount': "${fiat['max_amount']}", + 'image': "", + }), + ); } // TODO handle else } @@ -181,12 +192,12 @@ class SimplexAPI { Future<BuyResponse<SimplexQuote>> getQuote(SimplexQuote quote) async { try { await _prefs.init(); - String? userID = _prefs.userID; + final String? userID = _prefs.userID; - Map<String, String> headers = { + final Map<String, String> headers = { 'Content-Type': 'application/x-www-form-urlencoded', }; - Map<String, String> data = { + final Map<String, String> data = { 'ROUTE': 'quote', 'CRYPTO_TICKER': quote.crypto.ticker.toUpperCase(), 'FIAT_TICKER': quote.fiat.ticker.toUpperCase(), @@ -200,13 +211,14 @@ class SimplexAPI { if (userID != null) { data['USER_ID'] = userID; } - Uri url = _buildUri('api.php', data); + final Uri url = _buildUri('api.php', data); - var res = await client.get( + final res = await client.get( url: url, headers: headers, - proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.getProxyInfo() : null, + proxyInfo: Prefs.instance.useTor + ? TorService.sharedInstance.getProxyInfo() + : null, ); if (res.code != 200) { throw Exception('getQuote exception: statusCode= ${res.code}'); @@ -238,10 +250,11 @@ class SimplexAPI { // final Map<String, dynamic> lol = // Map<String, dynamic>.from(jsonArray as Map); - double? cryptoAmount = jsonArray['digital_money']?['amount'] as double?; + final double? cryptoAmount = + jsonArray['digital_money']?['amount'] as double?; if (cryptoAmount == null) { - String error = jsonArray['error'] as String; + final String error = jsonArray['error'] as String; return BuyResponse( exception: BuyException( error, @@ -250,7 +263,7 @@ class SimplexAPI { ); } - SimplexQuote quote = jsonArray['quote'] as SimplexQuote; + final SimplexQuote quote = jsonArray['quote'] as SimplexQuote; final SimplexQuote _quote = SimplexQuote( crypto: quote.crypto, fiat: quote.fiat, @@ -287,13 +300,13 @@ class SimplexAPI { // -d '{"account_details": {"app_provider_id": "$publicKey", "app_version_id": "123", "app_end_user_id": "01e7a0b9-8dfc-4988-a28d-84a34e5f0a63", "signup_login": {"timestamp": "1994-11-05T08:15:30-05:00", "ip": "207.66.86.226"}}, "transaction_details": {"payment_details": {"quote_id": "3b58f4b4-ed6f-447c-b96a-ffe97d7b6803", "payment_id": "baaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "order_id": "789", "original_http_ref_url": "https://stackwallet.com/simplex", "destination_wallet": {"currency": "BTC", "address": "bc1qjvj9ca8gdsv3g58yrzrk6jycvgnjh9uj35rja2"}}}}' try { await _prefs.init(); - String? userID = _prefs.userID; - int? signupEpoch = _prefs.signupEpoch; + final String? userID = _prefs.userID; + final int? signupEpoch = _prefs.signupEpoch; - Map<String, String> headers = { + final Map<String, String> headers = { 'Content-Type': 'application/x-www-form-urlencoded', }; - Map<String, String> data = { + final Map<String, String> data = { 'ROUTE': 'order', 'QUOTE_ID': quote.id, 'ADDRESS': quote.receivingAddress, @@ -303,17 +316,19 @@ class SimplexAPI { data['USER_ID'] = userID; } if (signupEpoch != null && signupEpoch != 0) { - DateTime date = DateTime.fromMillisecondsSinceEpoch(signupEpoch * 1000); + final DateTime date = + DateTime.fromMillisecondsSinceEpoch(signupEpoch * 1000); data['SIGNUP_TIMESTAMP'] = date.toIso8601String() + timeZoneFormatter(date.timeZoneOffset); } - Uri url = _buildUri('api.php', data); + final Uri url = _buildUri('api.php', data); - var res = await client.get( + final res = await client.get( url: url, headers: headers, - proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.getProxyInfo() : null, + proxyInfo: Prefs.instance.useTor + ? TorService.sharedInstance.getProxyInfo() + : null, ); if (res.code != 200) { throw Exception('newOrder exception: statusCode= ${res.code}'); @@ -325,7 +340,7 @@ class SimplexAPI { } } - SimplexOrder _order = SimplexOrder( + final SimplexOrder _order = SimplexOrder( quote: quote, paymentId: "${jsonArray['paymentId']}", orderId: "${jsonArray['orderId']}", @@ -346,16 +361,16 @@ class SimplexAPI { Future<BuyResponse<bool>> redirect(SimplexOrder order) async { try { - Map<String, String> headers = { + final Map<String, String> headers = { 'Content-Type': 'application/x-www-form-urlencoded', }; - Map<String, String> data = { + final Map<String, String> data = { 'ROUTE': 'redirect', 'PAYMENT_ID': order.paymentId, }; - Uri url = _buildUri('api.php', data); + final Uri url = _buildUri('api.php', data); - bool status = await launchUrl( + final bool status = await launchUrl( url, mode: LaunchMode.externalApplication, ); @@ -364,10 +379,11 @@ class SimplexAPI { } catch (e, s) { Logging.instance.log("newOrder exception: $e\n$s", level: LogLevel.Error); return BuyResponse( - exception: BuyException( - e.toString(), - BuyExceptionType.generic, - )); + exception: BuyException( + e.toString(), + BuyExceptionType.generic, + ), + ); } } @@ -389,7 +405,7 @@ bool isStackCoin(String? ticker) { if (ticker == null) return false; try { - coinFromTickerCaseInsensitive(ticker); + SupportedCoins.getCryptoCurrencyForTicker(ticker); return true; } on ArgumentError catch (_) { return false; diff --git a/lib/services/ethereum/ethereum_api.dart b/lib/services/ethereum/ethereum_api.dart index b9ac2224b..8d1aec4ae 100644 --- a/lib/services/ethereum/ethereum_api.dart +++ b/lib/services/ethereum/ethereum_api.dart @@ -20,11 +20,12 @@ import 'package:stackwallet/models/paymint/fee_object_model.dart'; import 'package:stackwallet/networking/http.dart'; import 'package:stackwallet/services/tor_service.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; -import 'package:stackwallet/utilities/default_nodes.dart'; import 'package:stackwallet/utilities/eth_commons.dart'; import 'package:stackwallet/utilities/extensions/extensions.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/prefs.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/ethereum.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:tuple/tuple.dart'; class EthApiException implements Exception { @@ -47,7 +48,8 @@ class EthereumResponse<T> { } abstract class EthereumAPI { - static String get stackBaseServer => DefaultNodes.ethereum.host; + static String get stackBaseServer => + Ethereum(CryptoCurrencyNetwork.main).defaultNode.host; static HTTP client = HTTP(); diff --git a/lib/services/event_bus/events/global/node_connection_status_changed_event.dart b/lib/services/event_bus/events/global/node_connection_status_changed_event.dart index 0361f3720..a0698409b 100644 --- a/lib/services/event_bus/events/global/node_connection_status_changed_event.dart +++ b/lib/services/event_bus/events/global/node_connection_status_changed_event.dart @@ -8,19 +8,20 @@ * */ -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/logger.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; enum NodeConnectionStatus { disconnected, connected } class NodeConnectionStatusChangedEvent { NodeConnectionStatus newStatus; String walletId; - Coin coin; + CryptoCurrency coin; NodeConnectionStatusChangedEvent(this.newStatus, this.walletId, this.coin) { Logging.instance.log( - "NodeConnectionStatusChangedEvent fired in $walletId with arg newStatus = $newStatus", - level: LogLevel.Info); + "NodeConnectionStatusChangedEvent fired in $walletId with arg newStatus = $newStatus", + level: LogLevel.Info, + ); } } diff --git a/lib/services/event_bus/events/global/wallet_sync_status_changed_event.dart b/lib/services/event_bus/events/global/wallet_sync_status_changed_event.dart index fb2a47614..4cb616909 100644 --- a/lib/services/event_bus/events/global/wallet_sync_status_changed_event.dart +++ b/lib/services/event_bus/events/global/wallet_sync_status_changed_event.dart @@ -8,19 +8,20 @@ * */ -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/logger.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; enum WalletSyncStatus { unableToSync, synced, syncing } class WalletSyncStatusChangedEvent { WalletSyncStatus newStatus; String walletId; - Coin coin; + CryptoCurrency coin; WalletSyncStatusChangedEvent(this.newStatus, this.walletId, this.coin) { Logging.instance.log( - "WalletSyncStatusChangedEvent fired in $walletId with arg newStatus = $newStatus", - level: LogLevel.Info); + "WalletSyncStatusChangedEvent fired in $walletId with arg newStatus = $newStatus", + level: LogLevel.Info, + ); } } diff --git a/lib/services/node_service.dart b/lib/services/node_service.dart index 88d032940..31e624be5 100644 --- a/lib/services/node_service.dart +++ b/lib/services/node_service.dart @@ -14,10 +14,11 @@ import 'package:flutter/material.dart'; import 'package:http/http.dart'; import 'package:stackwallet/db/hive/db.dart'; import 'package:stackwallet/models/node_model.dart'; +import 'package:stackwallet/supported_coins.dart'; import 'package:stackwallet/utilities/default_nodes.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'; import 'package:stackwallet/utilities/logger.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; const kStackCommunityNodesEndpoint = "https://extras.stackwallet.com"; @@ -30,12 +31,18 @@ class NodeService extends ChangeNotifier { }); Future<void> updateDefaults() async { - for (final defaultNode in DefaultNodes.all) { + for (final defaultNode in SupportedCoins.cryptocurrencies.map( + (e) => e.defaultNode, + )) { final savedNode = DB.instance .get<NodeModel>(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(coinFromPrettyName(defaultNode.coinName)).isEmpty) { + if (getNodesFor( + SupportedCoins.getCryptoCurrencyByPrettyName( + defaultNode.coinName, + ), + ).isEmpty) { await DB.instance.put<NodeModel>( boxName: DB.boxNameNodeModels, key: defaultNode.id, @@ -45,19 +52,21 @@ class NodeService extends ChangeNotifier { } else { // update all fields but copy over previously set enabled and trusted states await DB.instance.put<NodeModel>( - boxName: DB.boxNameNodeModels, - key: savedNode.id, - value: defaultNode.copyWith( - enabled: savedNode.enabled, - isFailover: savedNode.isFailover, - trusted: savedNode.trusted, - )); + boxName: DB.boxNameNodeModels, + key: savedNode.id, + value: defaultNode.copyWith( + enabled: savedNode.enabled, + isFailover: savedNode.isFailover, + trusted: savedNode.trusted, + ), + ); } // check if a default node is the primary node for the crypto currency // and update it if needed - final coin = coinFromPrettyName(defaultNode.coinName); - final primaryNode = getPrimaryNodeFor(coin: coin); + final coin = + SupportedCoins.getCryptoCurrencyByPrettyName(defaultNode.coinName); + final primaryNode = getPrimaryNodeFor(currency: coin); if (primaryNode != null && primaryNode.id == defaultNode.id) { await setPrimaryNodeFor( coin: coin, @@ -72,20 +81,25 @@ class NodeService extends ChangeNotifier { } Future<void> setPrimaryNodeFor({ - required Coin coin, + required CryptoCurrency coin, required NodeModel node, bool shouldNotifyListeners = false, }) async { await DB.instance.put<NodeModel>( - boxName: DB.boxNamePrimaryNodes, key: coin.name, value: node); + boxName: DB.boxNamePrimaryNodes, + key: coin.identifier, + value: node, + ); if (shouldNotifyListeners) { notifyListeners(); } } - NodeModel? getPrimaryNodeFor({required Coin coin}) { - return DB.instance - .get<NodeModel>(boxName: DB.boxNamePrimaryNodes, key: coin.name); + NodeModel? getPrimaryNodeFor({required CryptoCurrency currency}) { + return DB.instance.get<NodeModel>( + boxName: DB.boxNamePrimaryNodes, + key: currency.identifier, + ); } List<NodeModel> get primaryNodes { @@ -96,21 +110,27 @@ class NodeService extends ChangeNotifier { return DB.instance.values<NodeModel>(boxName: DB.boxNameNodeModels); } - List<NodeModel> getNodesFor(Coin coin) { + List<NodeModel> getNodesFor(CryptoCurrency coin) { final list = DB.instance .values<NodeModel>(boxName: DB.boxNameNodeModels) - .where((e) => - e.coinName == coin.name && - !e.id.startsWith(DefaultNodes.defaultNodeIdPrefix)) + .where( + (e) => + e.coinName == coin.identifier && + !e.id.startsWith(DefaultNodes.defaultNodeIdPrefix), + ) .toList(); // add default to end of list - list.addAll(DB.instance - .values<NodeModel>(boxName: DB.boxNameNodeModels) - .where((e) => - e.coinName == coin.name && - e.id.startsWith(DefaultNodes.defaultNodeIdPrefix)) - .toList()); + list.addAll( + DB.instance + .values<NodeModel>(boxName: DB.boxNameNodeModels) + .where( + (e) => + e.coinName == coin.identifier && + e.id.startsWith(DefaultNodes.defaultNodeIdPrefix), + ) + .toList(), + ); // return reversed list so default node appears at beginning return list.reversed.toList(); @@ -120,8 +140,10 @@ class NodeService extends ChangeNotifier { return DB.instance.get<NodeModel>(boxName: DB.boxNameNodeModels, key: id); } - List<NodeModel> failoverNodesFor({required Coin coin}) { - return getNodesFor(coin).where((e) => e.isFailover && !e.isDown).toList(); + List<NodeModel> failoverNodesFor({required CryptoCurrency currency}) { + return getNodesFor(currency) + .where((e) => e.isFailover && !e.isDown) + .toList(); } // should probably just combine this and edit into a save() func at some point @@ -133,11 +155,16 @@ class NodeService extends ChangeNotifier { bool shouldNotifyListeners, ) async { await DB.instance.put<NodeModel>( - boxName: DB.boxNameNodeModels, key: node.id, value: node); + boxName: DB.boxNameNodeModels, + key: node.id, + value: node, + ); if (password != null) { await secureStorageInterface.write( - key: "${node.id}_nodePW", value: password); + key: "${node.id}_nodePW", + value: password, + ); } if (shouldNotifyListeners) { notifyListeners(); @@ -163,9 +190,10 @@ class NodeService extends ChangeNotifier { key: id, )!; await DB.instance.put<NodeModel>( - boxName: DB.boxNameNodeModels, - key: model.id, - value: model.copyWith(enabled: enabled)); + boxName: DB.boxNameNodeModels, + key: model.id, + value: model.copyWith(enabled: enabled), + ); if (shouldNotifyListeners) { notifyListeners(); } @@ -178,8 +206,9 @@ class NodeService extends ChangeNotifier { bool shouldNotifyListeners, ) async { // check if the node being edited is the primary one; if it is, setPrimaryNodeFor coin - final coin = coinFromPrettyName(editedNode.coinName); - var primaryNode = getPrimaryNodeFor(coin: coin); + final coin = + SupportedCoins.getCryptoCurrencyByPrettyName(editedNode.coinName); + final primaryNode = getPrimaryNodeFor(currency: coin); if (primaryNode?.id == editedNode.id) { await setPrimaryNodeFor( coin: coin, @@ -211,9 +240,10 @@ class NodeService extends ChangeNotifier { final map = jsonDecode(result as String); Logging.instance.log(map, level: LogLevel.Info); - for (final coin in Coin.values) { + for (final coin in SupportedCoins.cryptocurrencies) { final nodeList = List<Map<String, dynamic>>.from( - map["nodes"][coin.name] as List? ?? []); + map["nodes"][coin.identifier] as List? ?? [], + ); for (final nodeMap in nodeList) { NodeModel node = NodeModel( host: nodeMap["host"] as String, @@ -222,7 +252,7 @@ class NodeService extends ChangeNotifier { id: nodeMap["id"] as String, useSSL: nodeMap["useSSL"] == "true", enabled: true, - coinName: coin.name, + coinName: coin.identifier, isFailover: true, isDown: nodeMap["isDown"] == "true", ); diff --git a/lib/services/notifications_service.dart b/lib/services/notifications_service.dart index 182de8747..528fe9ae5 100644 --- a/lib/services/notifications_service.dart +++ b/lib/services/notifications_service.dart @@ -21,9 +21,10 @@ import 'package:stackwallet/services/node_service.dart'; import 'package:stackwallet/services/notifications_api.dart'; import 'package:stackwallet/services/trade_service.dart'; import 'package:stackwallet/services/wallets.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/supported_coins.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/prefs.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart'; import 'exchange/exchange.dart'; @@ -55,15 +56,19 @@ class NotificationsService extends ChangeNotifier { Future<void> _addWatchedTxNotification(NotificationModel notification) async { await DB.instance.put<NotificationModel>( - boxName: DB.boxNameWatchedTransactions, - key: notification.id, - value: notification); + boxName: DB.boxNameWatchedTransactions, + key: notification.id, + value: notification, + ); } Future<void> _deleteWatchedTxNotification( - NotificationModel notification) async { + NotificationModel notification, + ) async { await DB.instance.delete<NotificationModel>( - boxName: DB.boxNameWatchedTransactions, key: notification.id); + boxName: DB.boxNameWatchedTransactions, + key: notification.id, + ); } // watched trades @@ -73,17 +78,22 @@ class NotificationsService extends ChangeNotifier { } Future<void> _addWatchedTradeNotification( - NotificationModel notification) async { + NotificationModel notification, + ) async { await DB.instance.put<NotificationModel>( - boxName: DB.boxNameWatchedTrades, - key: notification.id, - value: notification); + boxName: DB.boxNameWatchedTrades, + key: notification.id, + value: notification, + ); } Future<void> _deleteWatchedTradeNotification( - NotificationModel notification) async { + NotificationModel notification, + ) async { await DB.instance.delete<NotificationModel>( - boxName: DB.boxNameWatchedTrades, key: notification.id); + boxName: DB.boxNameWatchedTrades, + key: notification.id, + ); } static Timer? _timer; @@ -118,11 +128,12 @@ class NotificationsService extends ChangeNotifier { void _checkTransactions() async { for (final notification in _watchedTransactionNotifications) { try { - final Coin coin = coinFromPrettyName(notification.coinName); + final CryptoCurrency coin = + SupportedCoins.getCryptoCurrencyByPrettyName(notification.coinName); final txid = notification.txid!; final wallet = Wallets.sharedInstance.getWallet(notification.walletId); - final node = nodeService.getPrimaryNodeFor(coin: coin); + final node = nodeService.getPrimaryNodeFor(currency: coin); if (node != null) { if (wallet is ElectrumXInterface) { final eNode = ElectrumXNode( @@ -133,14 +144,16 @@ class NotificationsService extends ChangeNotifier { useSSL: node.useSSL, ); final failovers = nodeService - .failoverNodesFor(coin: coin) - .map((e) => ElectrumXNode( - address: e.host, - port: e.port, - name: e.name, - id: e.id, - useSSL: e.useSSL, - )) + .failoverNodesFor(currency: coin) + .map( + (e) => ElectrumXNode( + address: e.host, + port: e.port, + name: e.name, + id: e.id, + useSSL: e.useSSL, + ), + ) .toList(); final client = ElectrumXClient.from( @@ -280,7 +293,8 @@ class NotificationsService extends ChangeNotifier { return DB.instance .values<NotificationModel>(boxName: DB.boxNameNotifications) .where( - (element) => element.read == false && element.walletId == walletId) + (element) => element.read == false && element.walletId == walletId, + ) .isNotEmpty; } @@ -320,7 +334,9 @@ class NotificationsService extends ChangeNotifier { bool shouldNotifyListeners, ) async { await DB.instance.delete<NotificationModel>( - boxName: DB.boxNameNotifications, key: notification.id); + boxName: DB.boxNameNotifications, + key: notification.id, + ); await _deleteWatchedTradeNotification(notification); await _deleteWatchedTxNotification(notification); diff --git a/lib/services/price.dart b/lib/services/price.dart index 281372dcd..e572f4b3f 100644 --- a/lib/services/price.dart +++ b/lib/services/price.dart @@ -16,9 +16,10 @@ import 'package:flutter/foundation.dart'; import 'package:stackwallet/db/hive/db.dart'; import 'package:stackwallet/networking/http.dart'; import 'package:stackwallet/services/tor_service.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/supported_coins.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/prefs.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:tuple/tuple.dart'; class PriceAPI { @@ -43,10 +44,11 @@ class PriceAPI { } Future<void> _updateCachedPrices( - Map<Coin, Tuple2<Decimal, double>> data) async { + Map<CryptoCurrency, Tuple2<Decimal, double>> data, + ) async { final Map<String, dynamic> map = {}; - for (final coin in Coin.values) { + for (final coin in SupportedCoins.cryptocurrencies) { final entry = data[coin]; if (entry == null) { map[coin.prettyName] = ["0", 0.0]; @@ -59,26 +61,32 @@ class PriceAPI { .put<dynamic>(boxName: DB.boxNamePriceCache, key: 'cache', value: map); } - Map<Coin, Tuple2<Decimal, double>> get _cachedPrices { + Map<CryptoCurrency, Tuple2<Decimal, double>> get _cachedPrices { final map = DB.instance.get<dynamic>(boxName: DB.boxNamePriceCache, key: 'cache') as Map? ?? {}; // init with 0 final result = { - for (final coin in Coin.values) coin: Tuple2(Decimal.zero, 0.0) + for (final coin in SupportedCoins.cryptocurrencies) + coin: Tuple2(Decimal.zero, 0.0), }; for (final entry in map.entries) { - result[coinFromPrettyName(entry.key as String)] = Tuple2( - Decimal.parse(entry.value[0] as String), entry.value[1] as double); + result[SupportedCoins.getCryptoCurrencyByPrettyName( + entry.key as String, + )] = Tuple2( + Decimal.parse(entry.value[0] as String), + entry.value[1] as double, + ); } return result; } - Future<Map<Coin, Tuple2<Decimal, double>>> getPricesAnd24hChange( - {required String baseCurrency}) async { + Future<Map<CryptoCurrency, Tuple2<Decimal, double>>> getPricesAnd24hChange({ + required String baseCurrency, + }) async { final now = DateTime.now(); if (_lastUsedBaseCurrency != baseCurrency || now.difference(_lastCalled) > refreshIntervalDuration) { @@ -91,11 +99,13 @@ class PriceAPI { final externalCalls = Prefs.instance.externalCalls; if ((!Logger.isTestEnv && !externalCalls) || !(await Prefs.instance.isExternalCallsSet())) { - Logging.instance.log("User does not want to use external calls", - level: LogLevel.Info); + Logging.instance.log( + "User does not want to use external calls", + level: LogLevel.Info, + ); return _cachedPrices; } - Map<Coin, Tuple2<Decimal, double>> result = {}; + final Map<CryptoCurrency, Tuple2<Decimal, double>> result = {}; try { final uri = Uri.parse( "https://api.coingecko.com/api/v3/coins/markets?vs_currency" @@ -116,7 +126,7 @@ class PriceAPI { for (final map in coinGeckoData) { final String coinName = map["name"] as String; - final coin = coinFromPrettyName(coinName); + final coin = SupportedCoins.getCryptoCurrencyByPrettyName(coinName); final price = Decimal.parse(map["current_price"].toString()); final change24h = map["price_change_percentage_24h"] != null @@ -131,8 +141,10 @@ class PriceAPI { return _cachedPrices; } catch (e, s) { - Logging.instance.log("getPricesAnd24hChange($baseCurrency): $e\n$s", - level: LogLevel.Error); + Logging.instance.log( + "getPricesAnd24hChange($baseCurrency): $e\n$s", + level: LogLevel.Error, + ); // return previous cached values return _cachedPrices; } @@ -140,12 +152,14 @@ class PriceAPI { static Future<List<String>?> availableBaseCurrencies() async { final externalCalls = Prefs.instance.externalCalls; - HTTP client = HTTP(); + final HTTP client = HTTP(); if ((!Logger.isTestEnv && !externalCalls) || !(await Prefs.instance.isExternalCallsSet())) { - Logging.instance.log("User does not want to use external calls", - level: LogLevel.Info); + Logging.instance.log( + "User does not want to use external calls", + level: LogLevel.Info, + ); return null; } const uriString = @@ -163,8 +177,10 @@ class PriceAPI { final json = jsonDecode(response.body) as List<dynamic>; return List<String>.from(json); } catch (e, s) { - Logging.instance.log("availableBaseCurrencies() using $uriString: $e\n$s", - level: LogLevel.Error); + Logging.instance.log( + "availableBaseCurrencies() using $uriString: $e\n$s", + level: LogLevel.Error, + ); return null; } } @@ -181,8 +197,10 @@ class PriceAPI { final externalCalls = Prefs.instance.externalCalls; if ((!Logger.isTestEnv && !externalCalls) || !(await Prefs.instance.isExternalCallsSet())) { - Logging.instance.log("User does not want to use external calls", - level: LogLevel.Info); + Logging.instance.log( + "User does not want to use external calls", + level: LogLevel.Info, + ); return tokenPrices; } diff --git a/lib/services/price_service.dart b/lib/services/price_service.dart index 561aa184c..15e5dc437 100644 --- a/lib/services/price_service.dart +++ b/lib/services/price_service.dart @@ -17,7 +17,8 @@ import 'package:stackwallet/db/isar/main_db.dart'; import 'package:stackwallet/models/isar/models/isar_models.dart'; import 'package:stackwallet/networking/http.dart'; import 'package:stackwallet/services/price.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/supported_coins.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:tuple/tuple.dart'; class PriceService extends ChangeNotifier { @@ -28,15 +29,16 @@ class PriceService extends ChangeNotifier { final Duration updateInterval = const Duration(seconds: 60); Timer? _timer; - final Map<Coin, Tuple2<Decimal, double>> _cachedPrices = { - for (final coin in Coin.values) coin: Tuple2(Decimal.zero, 0.0) + final Map<CryptoCurrency, Tuple2<Decimal, double>> _cachedPrices = { + for (final coin in SupportedCoins.cryptocurrencies) + coin: Tuple2(Decimal.zero, 0.0) }; final Map<String, Tuple2<Decimal, double>> _cachedTokenPrices = {}; final _priceAPI = PriceAPI(HTTP()); - Tuple2<Decimal, double> getPrice(Coin coin) => _cachedPrices[coin]!; + Tuple2<Decimal, double> getPrice(CryptoCurrency coin) => _cachedPrices[coin]!; Tuple2<Decimal, double> getTokenPrice(String contractAddress) => _cachedTokenPrices[contractAddress.toLowerCase()] ?? diff --git a/lib/services/wallets.dart b/lib/services/wallets.dart index bba7bfe90..22daf7716 100644 --- a/lib/services/wallets.dart +++ b/lib/services/wallets.dart @@ -18,11 +18,11 @@ import 'package:stackwallet/db/isar/main_db.dart'; import 'package:stackwallet/services/node_service.dart'; import 'package:stackwallet/services/notifications_service.dart'; import 'package:stackwallet/services/trade_sent_from_stack_service.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/sync_type_enum.dart'; import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/prefs.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/epiccash.dart'; import 'package:stackwallet/wallets/isar/models/wallet_info.dart'; import 'package:stackwallet/wallets/wallet/impl/epiccash_wallet.dart'; import 'package:stackwallet/wallets/wallet/wallet.dart'; @@ -79,19 +79,19 @@ class Wallets { key: Wallet.mnemonicPassphraseKey(walletId: walletId)); await secureStorage.delete(key: Wallet.privateKeyKey(walletId: walletId)); - if (info.coin == Coin.wownero) { + if (info.coin is Wownero) { final wowService = wownero.createWowneroWalletService(DB.instance.moneroWalletInfoBox); await wowService.remove(walletId); Logging.instance .log("monero wallet: $walletId deleted", level: LogLevel.Info); - } else if (info.coin == Coin.monero) { + } else if (info.coin is Monero) { final xmrService = monero.createMoneroWalletService(DB.instance.moneroWalletInfoBox); await xmrService.remove(walletId); Logging.instance .log("monero wallet: $walletId deleted", level: LogLevel.Info); - } else if (info.coin == Coin.epicCash) { + } else if (info.coin is Epiccash) { final deleteResult = await deleteEpicWallet( walletId: walletId, secureStore: secureStorage); Logging.instance.log( diff --git a/lib/services/wallets_service.dart b/lib/services/wallets_service.dart index 738c9d6c6..8aab994d5 100644 --- a/lib/services/wallets_service.dart +++ b/lib/services/wallets_service.dart @@ -12,18 +12,18 @@ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:stackwallet/db/hive/db.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/supported_coins.dart'; import 'package:stackwallet/utilities/logger.dart'; @Deprecated("Legacy support only. Do not use.") class WalletInfo { - final Coin coin; + final String coinIdentifier; final String walletId; final String name; @Deprecated("Legacy support only. Do not use.") const WalletInfo({ - required this.coin, + required this.coinIdentifier, required this.walletId, required this.name, }); @@ -31,7 +31,7 @@ class WalletInfo { @Deprecated("Legacy support only. Do not use.") factory WalletInfo.fromJson(Map<String, dynamic> jsonObject) { return WalletInfo( - coin: Coin.values.byName(jsonObject["coin"] as String), + coinIdentifier: jsonObject["coin"] as String, walletId: jsonObject["id"] as String, name: jsonObject["name"] as String, ); @@ -42,7 +42,7 @@ class WalletInfo { return { "name": name, "id": walletId, - "coin": coin.name, + "coin": coinIdentifier, }; } @@ -75,12 +75,14 @@ class WalletsService extends ChangeNotifier { .get<dynamic>(boxName: DB.boxNameAllWalletsData, key: 'names') as Map?; if (names == null) { Logging.instance.log( - "Fetched wallet 'names' returned null. Setting initializing 'names'", - level: LogLevel.Info); + "Fetched wallet 'names' returned null. Setting initializing 'names'", + level: LogLevel.Info, + ); await DB.instance.put<dynamic>( - boxName: DB.boxNameAllWalletsData, - key: 'names', - value: <String, dynamic>{}); + boxName: DB.boxNameAllWalletsData, + key: 'names', + value: <String, dynamic>{}, + ); return {}; } Logging.instance.log("Fetched wallet names: $names", level: LogLevel.Info); @@ -88,16 +90,22 @@ class WalletsService extends ChangeNotifier { mapped.removeWhere((name, dyn) { final jsonObject = Map<String, dynamic>.from(dyn as Map); try { - Coin.values.byName(jsonObject["coin"] as String); + SupportedCoins.getCryptoCurrencyFor(jsonObject["coin"] as String); return false; } catch (e, s) { - Logging.instance.log("Error, ${jsonObject["coin"]} does not exist", - level: LogLevel.Error); + Logging.instance.log( + "Error, ${jsonObject["coin"]} does not exist", + level: LogLevel.Error, + ); return true; } }); - return mapped.map((name, dyn) => MapEntry( - name, WalletInfo.fromJson(Map<String, dynamic>.from(dyn as Map)))); + return mapped.map( + (name, dyn) => MapEntry( + name, + WalletInfo.fromJson(Map<String, dynamic>.from(dyn as Map)), + ), + ); } } diff --git a/lib/supported_coins.dart b/lib/supported_coins.dart index 70ee44ad8..70b6deae7 100644 --- a/lib/supported_coins.dart +++ b/lib/supported_coins.dart @@ -1,4 +1,3 @@ -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/wallets/crypto_currency/coins/banano.dart'; import 'package:stackwallet/wallets/crypto_currency/coins/bitcoin.dart'; import 'package:stackwallet/wallets/crypto_currency/coins/bitcoin_frost.dart'; @@ -19,72 +18,68 @@ import 'package:stackwallet/wallets/crypto_currency/coins/stellar.dart'; import 'package:stackwallet/wallets/crypto_currency/coins/tezos.dart'; import 'package:stackwallet/wallets/crypto_currency/coins/wownero.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; +import 'package:stackwallet/wallets/crypto_currency/intermediate/frost_currency.dart'; /// The supported coins. Eventually move away from the Coin enum class SupportedCoins { - /// A List of our supported coins. Piggy back on [Coin] for now - static final List<CryptoCurrency> cryptocurrencies = - Coin.values.map((e) => getCryptoCurrencyFor(e)).toList(growable: false); + /// A List of our supported coins. + static final List<CryptoCurrency> cryptocurrencies = [ + Bitcoin(CryptoCurrencyNetwork.main), + BitcoinFrost(CryptoCurrencyNetwork.main), + Litecoin(CryptoCurrencyNetwork.main), + Bitcoincash(CryptoCurrencyNetwork.main), + Dogecoin(CryptoCurrencyNetwork.main), + Epiccash(CryptoCurrencyNetwork.main), + Ecash(CryptoCurrencyNetwork.main), + Ethereum(CryptoCurrencyNetwork.main), + Firo(CryptoCurrencyNetwork.main), + Monero(CryptoCurrencyNetwork.main), + Particl(CryptoCurrencyNetwork.main), + Peercoin(CryptoCurrencyNetwork.main), + Solana(CryptoCurrencyNetwork.main), + Stellar(CryptoCurrencyNetwork.main), + Tezos(CryptoCurrencyNetwork.main), + Wownero(CryptoCurrencyNetwork.main), + Namecoin(CryptoCurrencyNetwork.main), + Nano(CryptoCurrencyNetwork.main), + Banano(CryptoCurrencyNetwork.main), + Bitcoin(CryptoCurrencyNetwork.test), + BitcoinFrost(CryptoCurrencyNetwork.test), + Litecoin(CryptoCurrencyNetwork.test), + Bitcoincash(CryptoCurrencyNetwork.test), + Firo(CryptoCurrencyNetwork.test), + Dogecoin(CryptoCurrencyNetwork.test), + Stellar(CryptoCurrencyNetwork.test), + Peercoin(CryptoCurrencyNetwork.test), + ]; - /// A getter function linking a [CryptoCurrency] with its associated [Coin]. - /// - /// Temporary: Remove when the Coin enum is removed. - static CryptoCurrency getCryptoCurrencyFor(Coin coin) { - switch (coin) { - case Coin.bitcoin: - return Bitcoin(CryptoCurrencyNetwork.main); - case Coin.bitcoinFrost: - return BitcoinFrost(CryptoCurrencyNetwork.main); - case Coin.litecoin: - return Litecoin(CryptoCurrencyNetwork.main); - case Coin.bitcoincash: - return Bitcoincash(CryptoCurrencyNetwork.main); - case Coin.dogecoin: - return Dogecoin(CryptoCurrencyNetwork.main); - case Coin.epicCash: - return Epiccash(CryptoCurrencyNetwork.main); - case Coin.eCash: - return Ecash(CryptoCurrencyNetwork.main); - case Coin.ethereum: - return Ethereum(CryptoCurrencyNetwork.main); - case Coin.firo: - return Firo(CryptoCurrencyNetwork.main); - case Coin.monero: - return Monero(CryptoCurrencyNetwork.main); - case Coin.particl: - return Particl(CryptoCurrencyNetwork.main); - case Coin.peercoin: - return Peercoin(CryptoCurrencyNetwork.main); - case Coin.solana: - return Solana(CryptoCurrencyNetwork.main); - case Coin.stellar: - return Stellar(CryptoCurrencyNetwork.main); - case Coin.tezos: - return Tezos(CryptoCurrencyNetwork.main); - case Coin.wownero: - return Wownero(CryptoCurrencyNetwork.main); - case Coin.namecoin: - return Namecoin(CryptoCurrencyNetwork.main); - case Coin.nano: - return Nano(CryptoCurrencyNetwork.main); - case Coin.banano: - return Banano(CryptoCurrencyNetwork.main); - case Coin.bitcoinTestNet: - return Bitcoin(CryptoCurrencyNetwork.test); - case Coin.bitcoinFrostTestNet: - return BitcoinFrost(CryptoCurrencyNetwork.test); - case Coin.litecoinTestNet: - return Litecoin(CryptoCurrencyNetwork.test); - case Coin.bitcoincashTestnet: - return Bitcoincash(CryptoCurrencyNetwork.test); - case Coin.firoTestNet: - return Firo(CryptoCurrencyNetwork.test); - case Coin.dogecoinTestNet: - return Dogecoin(CryptoCurrencyNetwork.test); - case Coin.stellarTestnet: - return Stellar(CryptoCurrencyNetwork.test); - case Coin.peercoinTestNet: - return Peercoin(CryptoCurrencyNetwork.test); + static CryptoCurrency getCryptoCurrencyFor(String coinIdentifier) => + cryptocurrencies.firstWhere( + (e) => e.identifier == coinIdentifier, + ); + + static CryptoCurrency getCryptoCurrencyForTicker( + final String ticker, { + bool caseInsensitive = true, + }) { + final _ticker = caseInsensitive ? ticker.toLowerCase() : ticker; + return cryptocurrencies.firstWhere( + caseInsensitive + ? (e) => e.ticker.toLowerCase() == _ticker && e is! FrostCurrency + : (e) => e.ticker == _ticker && e is! FrostCurrency, + ); + } + + /// Fuzzy logic. Use with caution!! + @Deprecated("dangerous") + static CryptoCurrency getCryptoCurrencyByPrettyName(final String prettyName) { + final name = prettyName.replaceAll(" ", "").toLowerCase(); + try { + return cryptocurrencies.firstWhere( + (e) => e.identifier.toLowerCase() == name || e.prettyName == prettyName, + ); + } catch (_) { + throw Exception("getCryptoCurrencyByPrettyName($prettyName) failed!"); } } } diff --git a/lib/themes/coin_card_provider.dart b/lib/themes/coin_card_provider.dart index b34e9e6f1..1e1b98ee8 100644 --- a/lib/themes/coin_card_provider.dart +++ b/lib/themes/coin_card_provider.dart @@ -11,24 +11,25 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/models/isar/stack_theme.dart'; import 'package:stackwallet/themes/theme_providers.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; -final coinCardProvider = Provider.family<String?, Coin>((ref, coin) { +final coinCardProvider = Provider.family<String?, CryptoCurrency>((ref, coin) { final assets = ref.watch(themeAssetsProvider); if (assets is ThemeAssetsV3) { - return assets.coinCardImages?[coin.mainNetVersion]; + return assets.coinCardImages?[coin.mainNetId]; } else { return null; } }); -final coinCardFavoritesProvider = Provider.family<String?, Coin>((ref, coin) { +final coinCardFavoritesProvider = + Provider.family<String?, CryptoCurrency>((ref, coin) { final assets = ref.watch(themeAssetsProvider); if (assets is ThemeAssetsV3) { - return assets.coinCardFavoritesImages?[coin.mainNetVersion] ?? - assets.coinCardImages?[coin.mainNetVersion]; + return assets.coinCardFavoritesImages?[coin.mainNetId] ?? + assets.coinCardImages?[coin.mainNetId]; } else { return null; } diff --git a/lib/themes/coin_icon_provider.dart b/lib/themes/coin_icon_provider.dart index 9bd3990bb..6415bc9c1 100644 --- a/lib/themes/coin_icon_provider.dart +++ b/lib/themes/coin_icon_provider.dart @@ -11,46 +11,52 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/models/isar/stack_theme.dart'; import 'package:stackwallet/themes/theme_providers.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/bitcoin.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/bitcoincash.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/dogecoin.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/epiccash.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/ethereum.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/litecoin.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/monero.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/namecoin.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/particl.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/wownero.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; -final coinIconProvider = Provider.family<String, Coin>((ref, coin) { +final coinIconProvider = Provider.family<String, CryptoCurrency>((ref, coin) { final assets = ref.watch(themeAssetsProvider); if (assets is ThemeAssets) { - switch (coin) { - case Coin.bitcoin: - case Coin.bitcoinTestNet: + switch (coin.runtimeType) { + case const (Bitcoin): return assets.bitcoin; - case Coin.litecoin: - case Coin.litecoinTestNet: + case const (Litecoin): return assets.litecoin; - case Coin.bitcoincash: - case Coin.bitcoincashTestnet: + case const (Bitcoincash): return assets.bitcoincash; - case Coin.dogecoin: - case Coin.dogecoinTestNet: + case const (Dogecoin): return assets.dogecoin; - case Coin.epicCash: + case const (Epiccash): return assets.epicCash; - case Coin.firo: - case Coin.firoTestNet: + case const (Firo): return assets.firo; - case Coin.monero: + case const (Monero): return assets.monero; - case Coin.wownero: + case const (Wownero): return assets.wownero; - case Coin.namecoin: + case const (Namecoin): return assets.namecoin; - case Coin.particl: + case const (Particl): return assets.particl; - case Coin.ethereum: + case const (Ethereum): return assets.ethereum; default: return assets.stackIcon; } } else if (assets is ThemeAssetsV2) { - return (assets).coinIcons[coin.mainNetVersion]!; + return (assets).coinIcons[coin.mainNetId]!; } else { - return (assets as ThemeAssetsV3).coinIcons[coin.mainNetVersion]!; + return (assets as ThemeAssetsV3).coinIcons[coin.mainNetId]!; } }); diff --git a/lib/themes/coin_image_provider.dart b/lib/themes/coin_image_provider.dart index 6ca839fb9..c73fc6af3 100644 --- a/lib/themes/coin_image_provider.dart +++ b/lib/themes/coin_image_provider.dart @@ -11,101 +11,31 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/models/isar/stack_theme.dart'; import 'package:stackwallet/themes/theme_providers.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; -final coinImageProvider = Provider.family<String, Coin>((ref, coin) { +final coinImageProvider = Provider.family<String, CryptoCurrency>((ref, coin) { final assets = ref.watch(themeAssetsProvider); if (assets is ThemeAssets) { - switch (coin) { - case Coin.bitcoin: - return assets.bitcoinImage; - case Coin.litecoin: - case Coin.litecoinTestNet: - return assets.litecoinImage; - case Coin.bitcoincash: - return assets.bitcoincashImage; - case Coin.dogecoin: - return assets.dogecoinImage; - case Coin.eCash: - return assets.bitcoinImage; - case Coin.epicCash: - return assets.epicCashImage; - case Coin.firo: - return assets.firoImage; - case Coin.monero: - return assets.moneroImage; - case Coin.wownero: - return assets.wowneroImage; - case Coin.namecoin: - return assets.namecoinImage; - case Coin.particl: - return assets.particlImage; - case Coin.bitcoinTestNet: - return assets.bitcoinImage; - case Coin.bitcoincashTestnet: - return assets.bitcoincashImage; - case Coin.firoTestNet: - return assets.firoImage; - case Coin.dogecoinTestNet: - return assets.dogecoinImage; - case Coin.ethereum: - return assets.ethereumImage; - default: - return assets.stackIcon; - } + // just update your wallet or theme + return assets.stackIcon; } else if (assets is ThemeAssetsV2) { - return (assets).coinImages[coin.mainNetVersion]!; + return (assets).coinImages[coin.mainNetId]!; } else { - return (assets as ThemeAssetsV3).coinImages[coin.mainNetVersion]!; + return (assets as ThemeAssetsV3).coinImages[coin.mainNetId]!; } }); -final coinImageSecondaryProvider = Provider.family<String, Coin>((ref, coin) { +final coinImageSecondaryProvider = + Provider.family<String, CryptoCurrency>((ref, coin) { final assets = ref.watch(themeAssetsProvider); if (assets is ThemeAssets) { - switch (coin) { - case Coin.bitcoin: - return assets.bitcoinImageSecondary; - case Coin.litecoin: - case Coin.litecoinTestNet: - return assets.litecoinImageSecondary; - case Coin.bitcoincash: - return assets.bitcoincashImageSecondary; - case Coin.dogecoin: - return assets.dogecoinImageSecondary; - case Coin.eCash: - return assets.bitcoinImageSecondary; - case Coin.epicCash: - return assets.epicCashImageSecondary; - case Coin.firo: - return assets.firoImageSecondary; - case Coin.monero: - return assets.moneroImageSecondary; - case Coin.wownero: - return assets.wowneroImageSecondary; - case Coin.namecoin: - return assets.namecoinImageSecondary; - case Coin.particl: - return assets.particlImageSecondary; - case Coin.bitcoinTestNet: - return assets.bitcoinImageSecondary; - case Coin.bitcoincashTestnet: - return assets.bitcoincashImageSecondary; - case Coin.firoTestNet: - return assets.firoImageSecondary; - case Coin.dogecoinTestNet: - return assets.dogecoinImageSecondary; - case Coin.ethereum: - return assets.ethereumImageSecondary; - - default: - return assets.stackIcon; - } + // just update your wallet or theme + return assets.stackIcon; } else if (assets is ThemeAssetsV2) { - return (assets).coinSecondaryImages[coin.mainNetVersion]!; + return (assets).coinSecondaryImages[coin.mainNetId]!; } else { - return (assets as ThemeAssetsV3).coinSecondaryImages[coin.mainNetVersion]!; + return (assets as ThemeAssetsV3).coinSecondaryImages[coin.mainNetId]!; } }); diff --git a/lib/themes/color_theme.dart b/lib/themes/color_theme.dart deleted file mode 100644 index e4dbcabc3..000000000 --- a/lib/themes/color_theme.dart +++ /dev/null @@ -1,88 +0,0 @@ -/* - * This file is part of Stack Wallet. - * - * Copyright (c) 2023 Cypher Stack - * All Rights Reserved. - * The code is distributed under GPLv3 license, see LICENSE file for details. - * Generated by Cypher Stack on 2023-05-26 - * - */ - -import 'package:flutter/material.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; - -const kCoinThemeColorDefaults = CoinThemeColorDefault(); - -class CoinThemeColorDefault { - const CoinThemeColorDefault(); - - Color get bitcoin => const Color(0xFFFCC17B); - Color get litecoin => const Color(0xFF7FA6E1); - Color get bitcoincash => const Color(0xFF7BCFB8); - Color get firo => const Color(0xFFFF897A); - Color get dogecoin => const Color(0xFFFFE079); - Color get epicCash => const Color(0xFFC5C7CB); - Color get eCash => const Color(0xFFC5C7CB); - Color get ethereum => const Color(0xFFA7ADE9); - Color get monero => const Color(0xFFFF9E6B); - Color get namecoin => const Color(0xFF91B1E1); - Color get wownero => const Color(0xFFED80C1); - Color get particl => const Color(0xFF8175BD); - Color get peercoin => const Color(0xFF3CB054); - Color get solana => const Color(0xFFC696FF); - Color get stellar => const Color(0xFF6600FF); - Color get nano => const Color(0xFF209CE9); - Color get banano => const Color(0xFFFBDD11); - Color get tezos => const Color(0xFF0F61FF); - - Color forCoin(Coin coin) { - switch (coin) { - case Coin.bitcoin: - case Coin.bitcoinTestNet: - case Coin.bitcoinFrost: - case Coin.bitcoinFrostTestNet: - return bitcoin; - case Coin.litecoin: - case Coin.litecoinTestNet: - return litecoin; - case Coin.bitcoincash: - case Coin.bitcoincashTestnet: - return bitcoincash; - case Coin.dogecoin: - case Coin.dogecoinTestNet: - return dogecoin; - case Coin.eCash: - return eCash; - case Coin.epicCash: - return epicCash; - case Coin.ethereum: - return ethereum; - case Coin.firo: - case Coin.firoTestNet: - return firo; - case Coin.monero: - return monero; - case Coin.namecoin: - return namecoin; - case Coin.wownero: - return wownero; - case Coin.particl: - return particl; - case Coin.peercoin: - return peercoin; - case Coin.peercoinTestNet: - return peercoin; - case Coin.solana: - return solana; - case Coin.stellar: - case Coin.stellarTestnet: - return stellar; - case Coin.nano: - return nano; - case Coin.banano: - return banano; - case Coin.tezos: - return tezos; - } - } -} diff --git a/lib/themes/stack_colors.dart b/lib/themes/stack_colors.dart index 11e146d1b..5f6823f86 100644 --- a/lib/themes/stack_colors.dart +++ b/lib/themes/stack_colors.dart @@ -10,8 +10,6 @@ import 'package:flutter/material.dart'; import 'package:stackwallet/models/isar/stack_theme.dart'; -import 'package:stackwallet/themes/color_theme.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; class StackColors extends ThemeExtension<StackColors> { final String themeId; @@ -1676,58 +1674,6 @@ class StackColors extends ThemeExtension<StackColors> { ); } - Color colorForCoin(Coin coin) { - switch (coin) { - case Coin.bitcoin: - case Coin.bitcoinTestNet: - case Coin.bitcoinFrost: - case Coin.bitcoinFrostTestNet: - return _coin.bitcoin; - case Coin.litecoin: - case Coin.litecoinTestNet: - return _coin.litecoin; - case Coin.bitcoincash: - case Coin.bitcoincashTestnet: - return _coin.bitcoincash; - case Coin.dogecoin: - case Coin.dogecoinTestNet: - return _coin.dogecoin; - case Coin.epicCash: - return _coin.epicCash; - case Coin.eCash: - return _coin.eCash; - case Coin.ethereum: - return _coin.ethereum; - case Coin.firo: - case Coin.firoTestNet: - return _coin.firo; - case Coin.monero: - return _coin.monero; - case Coin.namecoin: - return _coin.namecoin; - case Coin.wownero: - return _coin.wownero; - case Coin.particl: - return _coin.particl; - case Coin.peercoin: - case Coin.peercoinTestNet: - return _coin.peercoin; - case Coin.solana: - return _coin.solana; - case Coin.stellar: - case Coin.stellarTestnet: - return _coin.stellar; - case Coin.nano: - return _coin.nano; - case Coin.banano: - return _coin.banano; - case Coin.tezos: - return _coin.tezos; - } - } - - static const _coin = CoinThemeColorDefault(); - Color colorForStatus(String status) { switch (status) { case "New": diff --git a/lib/themes/theme_providers.dart b/lib/themes/theme_providers.dart index eb622e8cc..e1ab4a5e9 100644 --- a/lib/themes/theme_providers.dart +++ b/lib/themes/theme_providers.dart @@ -13,7 +13,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/models/isar/stack_theme.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/themes/theme_service.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; final applicationThemesDirectoryPathProvider = StateProvider((ref) => ""); @@ -41,10 +41,10 @@ final themeAssetsProvider = StateProvider<IThemeAssets>( ), ); -final pCoinColor = StateProvider.family<Color, Coin>( +final pCoinColor = StateProvider.family<Color, CryptoCurrency>( (ref, coin) => ref.watch( - themeProvider.select((value) => value.coinColors[coin.mainNetVersion]), + themeProvider.select((value) => value.coinColors[coin.mainNetId]), ) ?? Colors.deepOrangeAccent, ); diff --git a/lib/utilities/address_utils.dart b/lib/utilities/address_utils.dart index 65e0231fe..3420a8217 100644 --- a/lib/utilities/address_utils.dart +++ b/lib/utilities/address_utils.dart @@ -10,191 +10,172 @@ import 'dart:convert'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/logger.dart'; -import 'package:stackwallet/wallets/crypto_currency/coins/banano.dart'; -import 'package:stackwallet/wallets/crypto_currency/coins/bitcoin.dart'; -import 'package:stackwallet/wallets/crypto_currency/coins/bitcoin_frost.dart'; import 'package:stackwallet/wallets/crypto_currency/coins/bitcoincash.dart'; -import 'package:stackwallet/wallets/crypto_currency/coins/dogecoin.dart'; import 'package:stackwallet/wallets/crypto_currency/coins/ecash.dart'; -import 'package:stackwallet/wallets/crypto_currency/coins/epiccash.dart'; -import 'package:stackwallet/wallets/crypto_currency/coins/ethereum.dart'; -import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; -import 'package:stackwallet/wallets/crypto_currency/coins/litecoin.dart'; -import 'package:stackwallet/wallets/crypto_currency/coins/monero.dart'; -import 'package:stackwallet/wallets/crypto_currency/coins/namecoin.dart'; -import 'package:stackwallet/wallets/crypto_currency/coins/nano.dart'; -import 'package:stackwallet/wallets/crypto_currency/coins/particl.dart'; -import 'package:stackwallet/wallets/crypto_currency/coins/solana.dart'; -import 'package:stackwallet/wallets/crypto_currency/coins/stellar.dart'; -import 'package:stackwallet/wallets/crypto_currency/coins/tezos.dart'; -import 'package:stackwallet/wallets/crypto_currency/coins/wownero.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; -import '../wallets/crypto_currency/coins/peercoin.dart'; - class AddressUtils { static String condenseAddress(String address) { return '${address.substring(0, 5)}...${address.substring(address.length - 5)}'; } - static bool validateAddress(String address, Coin coin) { - //This calls the validate address for each crypto coin, validateAddress is - //only used in 2 places, so I just replaced the old functionality here - switch (coin) { - case Coin.bitcoin: - return Bitcoin(CryptoCurrencyNetwork.main).validateAddress(address); - case Coin.bitcoinFrost: - return BitcoinFrost(CryptoCurrencyNetwork.main) - .validateAddress(address); - case Coin.litecoin: - return Litecoin(CryptoCurrencyNetwork.main).validateAddress(address); - case Coin.bitcoincash: - return Bitcoincash(CryptoCurrencyNetwork.main).validateAddress(address); - case Coin.dogecoin: - return Dogecoin(CryptoCurrencyNetwork.main).validateAddress(address); - case Coin.epicCash: - return Epiccash(CryptoCurrencyNetwork.main).validateAddress(address); - case Coin.ethereum: - return Ethereum(CryptoCurrencyNetwork.main).validateAddress(address); - case Coin.firo: - return Firo(CryptoCurrencyNetwork.main).validateAddress(address); - case Coin.eCash: - return Ecash(CryptoCurrencyNetwork.main).validateAddress(address); - case Coin.monero: - return Monero(CryptoCurrencyNetwork.main).validateAddress(address); - case Coin.wownero: - return Wownero(CryptoCurrencyNetwork.main).validateAddress(address); - case Coin.namecoin: - return Namecoin(CryptoCurrencyNetwork.main).validateAddress(address); - case Coin.particl: - return Particl(CryptoCurrencyNetwork.main).validateAddress(address); - case Coin.peercoin: - return Peercoin(CryptoCurrencyNetwork.main).validateAddress(address); - case Coin.solana: - return Solana(CryptoCurrencyNetwork.main).validateAddress(address); - case Coin.stellar: - return Stellar(CryptoCurrencyNetwork.main).validateAddress(address); - case Coin.nano: - return Nano(CryptoCurrencyNetwork.main).validateAddress(address); - case Coin.banano: - return Banano(CryptoCurrencyNetwork.main).validateAddress(address); - case Coin.tezos: - return Tezos(CryptoCurrencyNetwork.main).validateAddress(address); - case Coin.bitcoinTestNet: - return Bitcoin(CryptoCurrencyNetwork.test).validateAddress(address); - case Coin.bitcoinFrostTestNet: - return BitcoinFrost(CryptoCurrencyNetwork.test) - .validateAddress(address); - case Coin.litecoinTestNet: - return Litecoin(CryptoCurrencyNetwork.test).validateAddress(address); - case Coin.bitcoincashTestnet: - return Bitcoincash(CryptoCurrencyNetwork.test).validateAddress(address); - case Coin.firoTestNet: - return Firo(CryptoCurrencyNetwork.test).validateAddress(address); - case Coin.dogecoinTestNet: - return Dogecoin(CryptoCurrencyNetwork.test).validateAddress(address); - case Coin.peercoinTestNet: - return Peercoin(CryptoCurrencyNetwork.test).validateAddress(address); - case Coin.stellarTestnet: - return Stellar(CryptoCurrencyNetwork.test).validateAddress(address); - } - // throw Exception("moved"); - // switch (coin) { - // case Coin.bitcoin: - // return Address.validateAddress(address, bitcoin); - // case Coin.litecoin: - // return Address.validateAddress(address, litecoin); - // case Coin.bitcoincash: - // try { - // // 0 for bitcoincash: address scheme, 1 for legacy address - // final format = bitbox.Address.detectFormat(address); - // - // if (coin == Coin.bitcoincashTestnet) { - // return true; - // } - // - // if (format == bitbox.Address.formatCashAddr) { - // String addr = address; - // if (addr.contains(":")) { - // addr = addr.split(":").last; - // } - // - // return addr.startsWith("q"); - // } else { - // return address.startsWith("1"); - // } - // } catch (e) { - // return false; - // } - // case Coin.dogecoin: - // return Address.validateAddress(address, dogecoin); - // case Coin.epicCash: - // return validateSendAddress(address) == "1"; - // case Coin.ethereum: - // return true; //TODO - validate ETH address - // case Coin.firo: - // return Address.validateAddress(address, firoNetwork); - // case Coin.eCash: - // return Address.validateAddress(address, eCashNetwork); - // case Coin.monero: - // return RegExp("[a-zA-Z0-9]{95}").hasMatch(address) || - // RegExp("[a-zA-Z0-9]{106}").hasMatch(address); - // case Coin.wownero: - // return RegExp("[a-zA-Z0-9]{95}").hasMatch(address) || - // RegExp("[a-zA-Z0-9]{106}").hasMatch(address); - // case Coin.namecoin: - // return Address.validateAddress(address, namecoin, namecoin.bech32!); - // case Coin.particl: - // return Address.validateAddress(address, particl); - // case Coin.stellar: - // return RegExp(r"^[G][A-Z0-9]{55}$").hasMatch(address); - // case Coin.nano: - // return NanoAccounts.isValid(NanoAccountType.NANO, address); - // case Coin.banano: - // return NanoAccounts.isValid(NanoAccountType.BANANO, address); - // case Coin.tezos: - // return RegExp(r"^tz[1-9A-HJ-NP-Za-km-z]{34}$").hasMatch(address); - // case Coin.bitcoinTestNet: - // return Address.validateAddress(address, testnet); - // case Coin.litecoinTestNet: - // return Address.validateAddress(address, litecointestnet); - // case Coin.bitcoincashTestnet: - // try { - // // 0 for bitcoincash: address scheme, 1 for legacy address - // final format = bitbox.Address.detectFormat(address); - // - // if (coin == Coin.bitcoincashTestnet) { - // return true; - // } - // - // if (format == bitbox.Address.formatCashAddr) { - // String addr = address; - // if (addr.contains(":")) { - // addr = addr.split(":").last; - // } - // - // return addr.startsWith("q"); - // } else { - // return address.startsWith("1"); - // } - // } catch (e) { - // return false; - // } - // case Coin.firoTestNet: - // return Address.validateAddress(address, firoTestNetwork); - // case Coin.dogecoinTestNet: - // return Address.validateAddress(address, dogecointestnet); - // case Coin.stellarTestnet: - // return RegExp(r"^[G][A-Z0-9]{55}$").hasMatch(address); - // } - } + // static bool validateAddress(String address, Coin coin) { + // //This calls the validate address for each crypto coin, validateAddress is + // //only used in 2 places, so I just replaced the old functionality here + // switch (coin) { + // case Coin.bitcoin: + // return Bitcoin(CryptoCurrencyNetwork.main).validateAddress(address); + // case Coin.bitcoinFrost: + // return BitcoinFrost(CryptoCurrencyNetwork.main) + // .validateAddress(address); + // case Coin.litecoin: + // return Litecoin(CryptoCurrencyNetwork.main).validateAddress(address); + // case Coin.bitcoincash: + // return Bitcoincash(CryptoCurrencyNetwork.main).validateAddress(address); + // case Coin.dogecoin: + // return Dogecoin(CryptoCurrencyNetwork.main).validateAddress(address); + // case Coin.epicCash: + // return Epiccash(CryptoCurrencyNetwork.main).validateAddress(address); + // case Coin.ethereum: + // return Ethereum(CryptoCurrencyNetwork.main).validateAddress(address); + // case Coin.firo: + // return Firo(CryptoCurrencyNetwork.main).validateAddress(address); + // case Coin.eCash: + // return Ecash(CryptoCurrencyNetwork.main).validateAddress(address); + // case Coin.monero: + // return Monero(CryptoCurrencyNetwork.main).validateAddress(address); + // case Coin.wownero: + // return Wownero(CryptoCurrencyNetwork.main).validateAddress(address); + // case Coin.namecoin: + // return Namecoin(CryptoCurrencyNetwork.main).validateAddress(address); + // case Coin.particl: + // return Particl(CryptoCurrencyNetwork.main).validateAddress(address); + // case Coin.peercoin: + // return Peercoin(CryptoCurrencyNetwork.main).validateAddress(address); + // case Coin.solana: + // return Solana(CryptoCurrencyNetwork.main).validateAddress(address); + // case Coin.stellar: + // return Stellar(CryptoCurrencyNetwork.main).validateAddress(address); + // case Coin.nano: + // return Nano(CryptoCurrencyNetwork.main).validateAddress(address); + // case Coin.banano: + // return Banano(CryptoCurrencyNetwork.main).validateAddress(address); + // case Coin.tezos: + // return Tezos(CryptoCurrencyNetwork.main).validateAddress(address); + // case Coin.bitcoinTestNet: + // return Bitcoin(CryptoCurrencyNetwork.test).validateAddress(address); + // case Coin.bitcoinFrostTestNet: + // return BitcoinFrost(CryptoCurrencyNetwork.test) + // .validateAddress(address); + // case Coin.litecoinTestNet: + // return Litecoin(CryptoCurrencyNetwork.test).validateAddress(address); + // case Coin.bitcoincashTestnet: + // return Bitcoincash(CryptoCurrencyNetwork.test).validateAddress(address); + // case Coin.firoTestNet: + // return Firo(CryptoCurrencyNetwork.test).validateAddress(address); + // case Coin.dogecoinTestNet: + // return Dogecoin(CryptoCurrencyNetwork.test).validateAddress(address); + // case Coin.peercoinTestNet: + // return Peercoin(CryptoCurrencyNetwork.test).validateAddress(address); + // case Coin.stellarTestnet: + // return Stellar(CryptoCurrencyNetwork.test).validateAddress(address); + // } + // // throw Exception("moved"); + // // switch (coin) { + // // case Coin.bitcoin: + // // return Address.validateAddress(address, bitcoin); + // // case Coin.litecoin: + // // return Address.validateAddress(address, litecoin); + // // case Coin.bitcoincash: + // // try { + // // // 0 for bitcoincash: address scheme, 1 for legacy address + // // final format = bitbox.Address.detectFormat(address); + // // + // // if (coin == Coin.bitcoincashTestnet) { + // // return true; + // // } + // // + // // if (format == bitbox.Address.formatCashAddr) { + // // String addr = address; + // // if (addr.contains(":")) { + // // addr = addr.split(":").last; + // // } + // // + // // return addr.startsWith("q"); + // // } else { + // // return address.startsWith("1"); + // // } + // // } catch (e) { + // // return false; + // // } + // // case Coin.dogecoin: + // // return Address.validateAddress(address, dogecoin); + // // case Coin.epicCash: + // // return validateSendAddress(address) == "1"; + // // case Coin.ethereum: + // // return true; //TODO - validate ETH address + // // case Coin.firo: + // // return Address.validateAddress(address, firoNetwork); + // // case Coin.eCash: + // // return Address.validateAddress(address, eCashNetwork); + // // case Coin.monero: + // // return RegExp("[a-zA-Z0-9]{95}").hasMatch(address) || + // // RegExp("[a-zA-Z0-9]{106}").hasMatch(address); + // // case Coin.wownero: + // // return RegExp("[a-zA-Z0-9]{95}").hasMatch(address) || + // // RegExp("[a-zA-Z0-9]{106}").hasMatch(address); + // // case Coin.namecoin: + // // return Address.validateAddress(address, namecoin, namecoin.bech32!); + // // case Coin.particl: + // // return Address.validateAddress(address, particl); + // // case Coin.stellar: + // // return RegExp(r"^[G][A-Z0-9]{55}$").hasMatch(address); + // // case Coin.nano: + // // return NanoAccounts.isValid(NanoAccountType.NANO, address); + // // case Coin.banano: + // // return NanoAccounts.isValid(NanoAccountType.BANANO, address); + // // case Coin.tezos: + // // return RegExp(r"^tz[1-9A-HJ-NP-Za-km-z]{34}$").hasMatch(address); + // // case Coin.bitcoinTestNet: + // // return Address.validateAddress(address, testnet); + // // case Coin.litecoinTestNet: + // // return Address.validateAddress(address, litecointestnet); + // // case Coin.bitcoincashTestnet: + // // try { + // // // 0 for bitcoincash: address scheme, 1 for legacy address + // // final format = bitbox.Address.detectFormat(address); + // // + // // if (coin == Coin.bitcoincashTestnet) { + // // return true; + // // } + // // + // // if (format == bitbox.Address.formatCashAddr) { + // // String addr = address; + // // if (addr.contains(":")) { + // // addr = addr.split(":").last; + // // } + // // + // // return addr.startsWith("q"); + // // } else { + // // return address.startsWith("1"); + // // } + // // } catch (e) { + // // return false; + // // } + // // case Coin.firoTestNet: + // // return Address.validateAddress(address, firoTestNetwork); + // // case Coin.dogecoinTestNet: + // // return Address.validateAddress(address, dogecointestnet); + // // case Coin.stellarTestnet: + // // return RegExp(r"^[G][A-Z0-9]{55}$").hasMatch(address); + // // } + // } /// parse an address uri /// returns an empty map if the input string does not begin with "firo:" static Map<String, String> parseUri(String uri) { - Map<String, String> result = {}; + final Map<String, String> result = {}; try { final u = Uri.parse(uri); if (u.hasScheme) { @@ -211,15 +192,13 @@ class AddressUtils { /// builds a uri string with the given address and query parameters if any static String buildUriString( - Coin coin, + CryptoCurrency coin, String address, Map<String, String> params, ) { // TODO: other sanitation as well ? String sanitizedAddress = address; - if (coin == Coin.bitcoincash || - coin == Coin.bitcoincashTestnet || - coin == Coin.eCash) { + if (coin is Bitcoincash || coin is Ecash) { final prefix = "${coin.uriScheme}:"; if (address.startsWith(prefix)) { sanitizedAddress = address.replaceFirst(prefix, ""); diff --git a/lib/utilities/amount/amount_formatter.dart b/lib/utilities/amount/amount_formatter.dart index 1ae577507..937636069 100644 --- a/lib/utilities/amount/amount_formatter.dart +++ b/lib/utilities/amount/amount_formatter.dart @@ -4,16 +4,16 @@ import 'package:stackwallet/providers/global/locale_provider.dart'; import 'package:stackwallet/providers/global/prefs_provider.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount_unit.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; -final pAmountUnit = Provider.family<AmountUnit, Coin>( +final pAmountUnit = Provider.family<AmountUnit, CryptoCurrency>( (ref, coin) => ref.watch( prefsChangeNotifierProvider.select( (value) => value.amountUnit(coin), ), ), ); -final pMaxDecimals = Provider.family<int, Coin>( +final pMaxDecimals = Provider.family<int, CryptoCurrency>( (ref, coin) => ref.watch( prefsChangeNotifierProvider.select( (value) => value.maxDecimals(coin), @@ -21,7 +21,8 @@ final pMaxDecimals = Provider.family<int, Coin>( ), ); -final pAmountFormatter = Provider.family<AmountFormatter, Coin>((ref, coin) { +final pAmountFormatter = + Provider.family<AmountFormatter, CryptoCurrency>((ref, coin) { final locale = ref.watch( localeServiceChangeNotifierProvider.select((value) => value.locale), ); @@ -37,7 +38,7 @@ final pAmountFormatter = Provider.family<AmountFormatter, Coin>((ref, coin) { class AmountFormatter { final AmountUnit unit; final String locale; - final Coin coin; + final CryptoCurrency coin; final int maxDecimals; AmountFormatter({ diff --git a/lib/utilities/amount/amount_unit.dart b/lib/utilities/amount/amount_unit.dart index e74de6510..a81559556 100644 --- a/lib/utilities/amount/amount_unit.dart +++ b/lib/utilities/amount/amount_unit.dart @@ -13,8 +13,12 @@ import 'dart:math' as math; import 'package:decimal/decimal.dart'; import 'package:stackwallet/models/isar/models/ethereum/eth_contract.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/ethereum.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/monero.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/wownero.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; +import 'package:stackwallet/wallets/crypto_currency/intermediate/nano_currency.dart'; // preserve index order as index is used to store value in preferences enum AmountUnit { @@ -34,48 +38,56 @@ enum AmountUnit { const AmountUnit(this.shift); final int shift; - static List<AmountUnit> valuesForCoin(Coin coin) { - switch (coin) { - case Coin.firo: - case Coin.litecoin: - case Coin.particl: - case Coin.peercoin: - case Coin.namecoin: - case Coin.bitcoinFrost: - case Coin.bitcoinFrostTestNet: - case Coin.bitcoinTestNet: - case Coin.litecoinTestNet: - case Coin.bitcoincashTestnet: - case Coin.dogecoinTestNet: - case Coin.firoTestNet: - case Coin.peercoinTestNet: - case Coin.bitcoin: - case Coin.bitcoincash: - case Coin.dogecoin: - case Coin.eCash: - case Coin.epicCash: - case Coin.stellar: // TODO: check if this is correct - case Coin.stellarTestnet: - case Coin.tezos: - case Coin.solana: - return AmountUnit.values.sublist(0, 4); - - case Coin.monero: - case Coin.wownero: - return AmountUnit.values.sublist(0, 5); - - case Coin.ethereum: - return AmountUnit.values.sublist(0, 7); - - case Coin.nano: - case Coin.banano: - return AmountUnit.values; + static List<AmountUnit> valuesForCoin(CryptoCurrency coin) { + final remainder = coin.fractionDigits % 3; + int n = (coin.fractionDigits ~/ 3) + 1; + if (remainder > 0) { + n++; } + + return AmountUnit.values.sublist(0, n); + // + // switch (coin) { + // case Coin.firo: + // case Coin.litecoin: + // case Coin.particl: + // case Coin.peercoin: + // case Coin.namecoin: + // case Coin.bitcoinFrost: + // case Coin.bitcoinFrostTestNet: + // case Coin.bitcoinTestNet: + // case Coin.litecoinTestNet: + // case Coin.bitcoincashTestnet: + // case Coin.dogecoinTestNet: + // case Coin.firoTestNet: + // case Coin.peercoinTestNet: + // case Coin.bitcoin: + // case Coin.bitcoincash: + // case Coin.dogecoin: + // case Coin.eCash: + // case Coin.epicCash: + // case Coin.stellar: // TODO: check if this is correct + // case Coin.stellarTestnet: + // case Coin.tezos: + // case Coin.solana: + // return AmountUnit.values.sublist(0, 4); + // + // case Coin.monero: + // case Coin.wownero: + // return AmountUnit.values.sublist(0, 5); + // + // case Coin.ethereum: + // return AmountUnit.values.sublist(0, 7); + // + // case Coin.nano: + // case Coin.banano: + // return AmountUnit.values; + // } } } extension AmountUnitExt on AmountUnit { - String unitForCoin(Coin coin) { + String unitForCoin(CryptoCurrency coin) { switch (this) { case AmountUnit.normal: return coin.ticker; @@ -84,63 +96,57 @@ extension AmountUnitExt on AmountUnit { case AmountUnit.micro: return "µ${coin.ticker}"; case AmountUnit.nano: - if (coin == Coin.ethereum) { + if (coin is Ethereum) { return "gwei"; - } else if (coin == Coin.wownero || - coin == Coin.monero || - coin == Coin.nano || - coin == Coin.banano) { + } else if (coin is Wownero || coin is Monero || coin is NanoCurrency) { return "n${coin.ticker}"; } else { return "sats"; } case AmountUnit.pico: - if (coin == Coin.ethereum) { + if (coin is Ethereum) { return "mwei"; - } else if (coin == Coin.wownero || - coin == Coin.monero || - coin == Coin.nano || - coin == Coin.banano) { + } else if (coin is Wownero || coin is Monero || coin is NanoCurrency) { return "p${coin.ticker}"; } else { return "invalid"; } case AmountUnit.femto: - if (coin == Coin.ethereum) { + if (coin is Ethereum) { return "kwei"; - } else if (coin == Coin.nano || coin == Coin.banano) { + } else if (coin is NanoCurrency) { return "f${coin.ticker}"; } else { return "invalid"; } case AmountUnit.atto: - if (coin == Coin.ethereum) { + if (coin is Ethereum) { return "wei"; - } else if (coin == Coin.nano || coin == Coin.banano) { + } else if (coin is NanoCurrency) { return "a${coin.ticker}"; } else { return "invalid"; } case AmountUnit.zepto: - if (coin == Coin.nano || coin == Coin.banano) { + if (coin is NanoCurrency) { return "z${coin.ticker}"; } else { return "invalid"; } case AmountUnit.yocto: - if (coin == Coin.nano || coin == Coin.banano) { + if (coin is NanoCurrency) { return "y${coin.ticker}"; } else { return "invalid"; } case AmountUnit.ronto: - if (coin == Coin.nano || coin == Coin.banano) { + if (coin is NanoCurrency) { return "r${coin.ticker}"; } else { return "invalid"; } case AmountUnit.quecto: - if (coin == Coin.nano || coin == Coin.banano) { + if (coin is NanoCurrency) { return "q${coin.ticker}"; } else { return "invalid"; @@ -174,7 +180,7 @@ extension AmountUnitExt on AmountUnit { Amount? tryParse( String value, { required String locale, - required Coin coin, + required CryptoCurrency coin, EthContract? tokenContract, bool overrideWithDecimalPlacesFromString = false, }) { @@ -212,7 +218,7 @@ extension AmountUnitExt on AmountUnit { final decimalPlaces = overrideWithDecimalPlacesFromString ? decimal.scale - : tokenContract?.decimals ?? coin.decimals; + : tokenContract?.decimals ?? coin.fractionDigits; final realShift = math.min(shift, decimalPlaces); return decimal.shift(0 - realShift).toAmount(fractionDigits: decimalPlaces); @@ -221,7 +227,7 @@ extension AmountUnitExt on AmountUnit { String displayAmount({ required Amount amount, required String locale, - required Coin coin, + required CryptoCurrency coin, required int maxDecimalPlaces, bool withUnitName = true, bool indicatePrecisionLoss = true, @@ -271,8 +277,9 @@ extension AmountUnitExt on AmountUnit { ? tokenContract.decimals : maxDecimalPlaces; } else { - updatedMax = - maxDecimalPlaces > coin.decimals ? coin.decimals : maxDecimalPlaces; + updatedMax = maxDecimalPlaces > coin.fractionDigits + ? coin.fractionDigits + : maxDecimalPlaces; } final int actualDecimalPlaces = math.min(places, updatedMax); diff --git a/lib/utilities/block_explorers.dart b/lib/utilities/block_explorers.dart index cf67697b6..b72b4a851 100644 --- a/lib/utilities/block_explorers.dart +++ b/lib/utilities/block_explorers.dart @@ -10,75 +10,11 @@ import 'package:stackwallet/db/isar/main_db.dart'; import 'package:stackwallet/models/isar/models/block_explorer.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; - -// Returns the default block explorer URL for the given coin and txid -Uri getDefaultBlockExplorerUrlFor({ - required Coin coin, - required String txid, -}) { - switch (coin) { - case Coin.bitcoinFrost: - case Coin.bitcoin: - return Uri.parse("https://mempool.space/tx/$txid"); - case Coin.litecoin: - return Uri.parse("https://chain.so/tx/LTC/$txid"); - case Coin.litecoinTestNet: - return Uri.parse("https://chain.so/tx/LTCTEST/$txid"); - case Coin.bitcoinTestNet: - case Coin.bitcoinFrostTestNet: - return Uri.parse("https://mempool.space/testnet/tx/$txid"); - case Coin.dogecoin: - return Uri.parse("https://chain.so/tx/DOGE/$txid"); - case Coin.eCash: - return Uri.parse("https://explorer.e.cash/tx/$txid"); - case Coin.dogecoinTestNet: - return Uri.parse("https://chain.so/tx/DOGETEST/$txid"); - case Coin.epicCash: - // TODO: Handle this case. - throw UnimplementedError("missing block explorer for epic cash"); - case Coin.ethereum: - return Uri.parse("https://etherscan.io/tx/$txid"); - case Coin.monero: - return Uri.parse("https://xmrchain.net/tx/$txid"); - case Coin.wownero: - return Uri.parse("https://explore.wownero.com/search?value=$txid"); - case Coin.firo: - return Uri.parse("https://explorer.firo.org/tx/$txid"); - case Coin.firoTestNet: - return Uri.parse("https://testexplorer.firo.org/tx/$txid"); - case Coin.bitcoincash: - return Uri.parse("https://blockchair.com/bitcoin-cash/transaction/$txid"); - case Coin.bitcoincashTestnet: - return Uri.parse( - "https://blockexplorer.one/bitcoin-cash/testnet/tx/$txid"); - case Coin.namecoin: - return Uri.parse("https://chainz.cryptoid.info/nmc/tx.dws?$txid.htm"); - case Coin.particl: - return Uri.parse("https://chainz.cryptoid.info/part/tx.dws?$txid.htm"); - case Coin.stellar: - return Uri.parse("https://stellarchain.io/tx/$txid"); - case Coin.nano: - return Uri.parse("https://www.nanolooker.com/block/$txid"); - case Coin.banano: - return Uri.parse("https://www.bananolooker.com/block/$txid"); - case Coin.stellarTestnet: - return Uri.parse("https://testnet.stellarchain.io/transactions/$txid"); - case Coin.tezos: - return Uri.parse("https://tzstats.com/$txid"); - case Coin.solana: - return Uri.parse("https://explorer.solana.com/tx/$txid"); - case Coin.peercoin: - return Uri.parse("https://chainz.cryptoid.info/ppc/tx.dws?$txid.htm"); - case Coin.peercoinTestNet: - return Uri.parse( - "https://chainz.cryptoid.info/ppc-test/search.dws?q=$txid.htm"); - } -} +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; // Returns internal Isar ID for the inserted object/record Future<int> setBlockExplorerForCoin({ - required Coin coin, + required CryptoCurrency coin, required Uri url, }) async { return await MainDB.instance.putTransactionBlockExplorer( @@ -91,12 +27,13 @@ Future<int> setBlockExplorerForCoin({ // Returns the block explorer URL for the given coin and txid Uri getBlockExplorerTransactionUrlFor({ - required Coin coin, + required CryptoCurrency coin, required String txid, }) { - String? url = MainDB.instance.getTransactionBlockExplorer(coin: coin)?.url; + String? url = + MainDB.instance.getTransactionBlockExplorer(cryptoCurrency: coin)?.url; if (url == null) { - return getDefaultBlockExplorerUrlFor(coin: coin, txid: txid); + return coin.defaultBlockExplorer(txid); } else { url = url.replaceAll("%5BTXID%5D", txid); return Uri.parse(url); diff --git a/lib/utilities/constants.dart b/lib/utilities/constants.dart index d3fedc666..5971d02f3 100644 --- a/lib/utilities/constants.dart +++ b/lib/utilities/constants.dart @@ -10,7 +10,6 @@ import 'dart:io'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/util.dart'; class _LayoutSizing { @@ -34,31 +33,6 @@ abstract class Constants { // just use enable exchange flag // static bool enableBuy = enableExchange; // // true; // true for development, - static final BigInt _satsPerCoinECash = BigInt.from(100); - static final BigInt _satsPerCoinEthereum = BigInt.from(1000000000000000000); - static final BigInt _satsPerCoinMonero = BigInt.from(1000000000000); - static final BigInt _satsPerCoinWownero = BigInt.from(100000000000); - static final BigInt _satsPerCoinNano = - BigInt.parse("1000000000000000000000000000000"); // 1*10^30 - static final BigInt _satsPerCoinBanano = - BigInt.parse("100000000000000000000000000000"); // 1*10^29 - static final BigInt _satsPerCoinStellar = BigInt.from( - 10000000); // https://developers.stellar.org/docs/fundamentals-and-concepts/stellar-data-structures/assets#amount-precision - static final BigInt _satsPerCoin = BigInt.from(100000000); - static final BigInt _satsPerCoinTezos = BigInt.from(1000000); - static final BigInt _satsPerCoinSolana = BigInt.from(1000000000); - static final BigInt _satsPerCoinPeercoin = BigInt.from(1000000); // 1*10^6. - static const int _decimalPlaces = 8; - static const int _decimalPlacesNano = 30; - static const int _decimalPlacesBanano = 29; - static const int _decimalPlacesWownero = 11; - static const int _decimalPlacesMonero = 12; - static const int _decimalPlacesEthereum = 18; - static const int _decimalPlacesECash = 2; - static const int _decimalPlacesStellar = 7; - static const int _decimalPlacesTezos = 6; - static const int _decimalPlacesSolana = 9; - static const int _decimalPlacesPeercoin = 6; static const int notificationsMax = 0xFFFFFFFF; static const Duration networkAliveTimerDuration = Duration(seconds: 10); @@ -70,264 +44,6 @@ abstract class Constants { static const int rescanV1 = 1; - static BigInt satsPerCoin(Coin coin) { - switch (coin) { - case Coin.bitcoin: - case Coin.bitcoinFrost: - case Coin.litecoin: - case Coin.litecoinTestNet: - case Coin.bitcoincash: - case Coin.bitcoincashTestnet: - case Coin.dogecoin: - case Coin.firo: - case Coin.bitcoinTestNet: - case Coin.bitcoinFrostTestNet: - case Coin.dogecoinTestNet: - case Coin.firoTestNet: - case Coin.epicCash: - case Coin.namecoin: - case Coin.particl: - return _satsPerCoin; - - case Coin.nano: - return _satsPerCoinNano; - - case Coin.banano: - return _satsPerCoinBanano; - - case Coin.wownero: - return _satsPerCoinWownero; - - case Coin.monero: - return _satsPerCoinMonero; - - case Coin.ethereum: - return _satsPerCoinEthereum; - - case Coin.eCash: - return _satsPerCoinECash; - - case Coin.stellar: - case Coin.stellarTestnet: - return _satsPerCoinStellar; - - case Coin.tezos: - return _satsPerCoinTezos; - - case Coin.solana: - return _satsPerCoinSolana; - - case Coin.peercoin: - case Coin.peercoinTestNet: - return _satsPerCoinPeercoin; - } - } - - static int decimalPlacesForCoin(Coin coin) { - switch (coin) { - case Coin.bitcoin: - case Coin.bitcoinFrost: - case Coin.litecoin: - case Coin.litecoinTestNet: - case Coin.bitcoincash: - case Coin.bitcoincashTestnet: - case Coin.dogecoin: - case Coin.firo: - case Coin.bitcoinTestNet: - case Coin.bitcoinFrostTestNet: - case Coin.dogecoinTestNet: - case Coin.firoTestNet: - case Coin.epicCash: - case Coin.namecoin: - case Coin.particl: - return _decimalPlaces; - - case Coin.nano: - return _decimalPlacesNano; - - case Coin.banano: - return _decimalPlacesBanano; - - case Coin.wownero: - return _decimalPlacesWownero; - - case Coin.monero: - return _decimalPlacesMonero; - - case Coin.ethereum: - return _decimalPlacesEthereum; - - case Coin.eCash: - return _decimalPlacesECash; - - case Coin.stellar: - case Coin.stellarTestnet: - return _decimalPlacesStellar; - - case Coin.tezos: - return _decimalPlacesTezos; - - case Coin.solana: - return _decimalPlacesSolana; - - case Coin.peercoin: - case Coin.peercoinTestNet: - return _decimalPlacesPeercoin; - } - } - - static List<int> possibleLengthsForCoin(Coin coin) { - final List<int> values = []; - switch (coin) { - case Coin.bitcoin: - case Coin.litecoin: - case Coin.litecoinTestNet: - case Coin.bitcoincash: - case Coin.bitcoincashTestnet: - case Coin.dogecoin: - case Coin.firo: - case Coin.bitcoinTestNet: - case Coin.dogecoinTestNet: - case Coin.firoTestNet: - case Coin.eCash: - case Coin.epicCash: - case Coin.ethereum: - case Coin.namecoin: - case Coin.particl: - values.addAll([12, 24]); - break; - case Coin.solana: - case Coin.nano: - case Coin.stellar: - case Coin.stellarTestnet: - values.addAll([24, 12]); - break; - case Coin.banano: - values.addAll([24, 12]); - break; - case Coin.tezos: - values.addAll([24, 12]); - - case Coin.monero: - values.addAll([25]); - break; - case Coin.wownero: - values.addAll([14, 25]); - break; - - case Coin.bitcoinFrost: - case Coin.bitcoinFrostTestNet: - throw ArgumentError("Frost mnemonic lengths unsupported"); - case Coin.peercoin: - case Coin.peercoinTestNet: - values.addAll([12, /*15, 18, 21,*/ 24]); // TODO [prio=low]: Test rest. - break; - } - return values; - } - - static int targetBlockTimeInSeconds(Coin coin) { - // TODO verify values - switch (coin) { - case Coin.bitcoin: - case Coin.bitcoinTestNet: - case Coin.bitcoinFrost: - case Coin.bitcoinFrostTestNet: - case Coin.bitcoincash: - case Coin.bitcoincashTestnet: - case Coin.eCash: - case Coin.peercoin: - case Coin.peercoinTestNet: - return 600; - - case Coin.dogecoin: - case Coin.dogecoinTestNet: - return 60; - - case Coin.litecoin: - case Coin.litecoinTestNet: - return 150; - - case Coin.firo: - case Coin.firoTestNet: - return 150; - - case Coin.epicCash: - return 60; - - case Coin.ethereum: - return 15; - - case Coin.monero: - return 120; - - case Coin.wownero: - return 120; - - case Coin.namecoin: - return 600; - - case Coin.particl: - return 600; - - case Coin.nano: // TODO: Verify this - case Coin.banano: // TODO: Verify this - case Coin.solana: - return 1; - - case Coin.stellar: - case Coin.stellarTestnet: - return 5; - - case Coin.tezos: - return 60; - } - } - - static int defaultSeedPhraseLengthFor({required Coin coin}) { - switch (coin) { - case Coin.bitcoin: - case Coin.bitcoinTestNet: - case Coin.bitcoincash: - case Coin.bitcoincashTestnet: - case Coin.eCash: - case Coin.dogecoin: - case Coin.dogecoinTestNet: - case Coin.litecoin: - case Coin.litecoinTestNet: - case Coin.firo: - case Coin.firoTestNet: - case Coin.namecoin: - case Coin.particl: - case Coin.ethereum: - case Coin.solana: - return 12; - - case Coin.wownero: - return 14; - - case Coin.nano: - case Coin.banano: - case Coin.epicCash: - case Coin.peercoin: // TODO [prio=low]: Verify default seed length. - case Coin.peercoinTestNet: - case Coin.stellar: - case Coin.stellarTestnet: - case Coin.tezos: - return 24; - - case Coin.monero: - return 25; - - case Coin.bitcoinFrost: - case Coin.bitcoinFrostTestNet: - throw ArgumentError("Frost mnemonic length unsupported"); - // - // default: - // -1; - } - } - static const Map<int, String> monthMapShort = { 1: 'Jan', 2: 'Feb', diff --git a/lib/utilities/default_nodes.dart b/lib/utilities/default_nodes.dart index 2e2bd71cc..f7f09583a 100644 --- a/lib/utilities/default_nodes.dart +++ b/lib/utilities/default_nodes.dart @@ -8,401 +8,11 @@ * */ -import 'package:stackwallet/models/node_model.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; abstract class DefaultNodes { static const String defaultNodeIdPrefix = "default_"; - static String buildId(Coin coin) => "$defaultNodeIdPrefix${coin.name}"; + static String buildId(CryptoCurrency cryptoCurrency) => + "$defaultNodeIdPrefix${cryptoCurrency.identifier}"; static const String defaultName = "Stack Default"; - - @Deprecated("old and decrepit") - static List<NodeModel> get all => Coin.values - .map((e) => DefaultNodes.getNodeFor(e)) - .toList(growable: false); - - static NodeModel get bitcoin => NodeModel( - host: "bitcoin.stackwallet.com", - port: 50002, - name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.bitcoin), - useSSL: true, - enabled: true, - coinName: Coin.bitcoin.name, - isFailover: true, - isDown: false, - ); - - static NodeModel get litecoin => NodeModel( - host: "litecoin.stackwallet.com", - port: 20063, - name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.litecoin), - useSSL: true, - enabled: true, - coinName: Coin.litecoin.name, - isFailover: true, - isDown: false, - ); - - static NodeModel get litecoinTestNet => NodeModel( - host: "litecoin.stackwallet.com", - port: 51002, - name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.litecoinTestNet), - useSSL: true, - enabled: true, - coinName: Coin.litecoinTestNet.name, - isFailover: true, - isDown: false, - ); - - static NodeModel get bitcoincash => NodeModel( - host: "bitcoincash.stackwallet.com", - port: 50002, - name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.bitcoincash), - useSSL: true, - enabled: true, - coinName: Coin.bitcoincash.name, - isFailover: true, - isDown: false, - ); - - static NodeModel get dogecoin => NodeModel( - host: "dogecoin.stackwallet.com", - port: 50022, - name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.dogecoin), - useSSL: true, - enabled: true, - coinName: Coin.dogecoin.name, - isFailover: true, - isDown: false, - ); - - static NodeModel get firo => NodeModel( - host: "firo.stackwallet.com", - port: 50002, - name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.firo), - useSSL: true, - enabled: true, - coinName: Coin.firo.name, - isFailover: true, - isDown: false, - ); - - static NodeModel get monero => NodeModel( - host: "https://monero.stackwallet.com", - port: 18081, - name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.monero), - useSSL: true, - enabled: true, - coinName: Coin.monero.name, - isFailover: true, - isDown: false, - trusted: true, - ); - - static NodeModel get wownero => NodeModel( - host: "https://wownero.stackwallet.com", - port: 34568, - name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.wownero), - useSSL: true, - enabled: true, - coinName: Coin.wownero.name, - isFailover: true, - isDown: false, - trusted: true, - ); - - static NodeModel get epicCash => NodeModel( - host: "http://epiccash.stackwallet.com", - port: 3413, - name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.epicCash), - useSSL: false, - enabled: true, - coinName: Coin.epicCash.name, - isFailover: true, - isDown: false, - ); - - static NodeModel get ethereum => NodeModel( - host: "https://eth.stackwallet.com", - port: 443, - name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.ethereum), - useSSL: true, - enabled: true, - coinName: Coin.ethereum.name, - isFailover: true, - isDown: false, - ); - - static NodeModel get namecoin => NodeModel( - host: "namecoin.stackwallet.com", - port: 57002, - name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.namecoin), - useSSL: true, - enabled: true, - coinName: Coin.namecoin.name, - isFailover: true, - isDown: false, - ); - - static NodeModel get particl => NodeModel( - host: "particl.stackwallet.com", - port: 58002, - name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.particl), - useSSL: true, - enabled: true, - coinName: Coin.particl.name, - isFailover: true, - isDown: false, - ); - - static NodeModel get peercoin => NodeModel( - host: "electrum.peercoinexplorer.net", - port: 50002, - name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.peercoin), - useSSL: true, - enabled: true, - coinName: Coin.peercoin.name, - isFailover: true, - isDown: false, - ); - - static NodeModel get solana => NodeModel( - host: - "https://api.mainnet-beta.solana.com", // TODO: Change this to stack wallet one - port: 443, - name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.solana), - useSSL: true, - enabled: true, - coinName: Coin.solana.name, - isFailover: true, - isDown: false, - ); - - static NodeModel get stellar => NodeModel( - host: "https://horizon.stellar.org", - port: 443, - name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.stellar), - useSSL: false, - enabled: true, - coinName: Coin.stellar.name, - isFailover: true, - isDown: false, - ); - - static NodeModel get tezos => NodeModel( - // TODO: Change this to stack wallet one - host: "https://mainnet.api.tez.ie", - port: 443, - name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.tezos), - useSSL: true, - enabled: true, - coinName: Coin.tezos.name, - isFailover: true, - isDown: false, - ); - - static NodeModel get nano => NodeModel( - host: "https://rainstorm.city/api", - port: 443, - name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.nano), - useSSL: true, - enabled: true, - coinName: Coin.nano.name, - isFailover: true, - isDown: false, - ); - - static NodeModel get banano => NodeModel( - host: "https://kaliumapi.appditto.com/api", - port: 443, - name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.banano), - useSSL: true, - enabled: true, - coinName: Coin.banano.name, - isFailover: true, - isDown: false, - ); - - static NodeModel get bitcoinTestnet => NodeModel( - host: "bitcoin-testnet.stackwallet.com", - port: 51002, - name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.bitcoinTestNet), - useSSL: true, - enabled: true, - coinName: Coin.bitcoinTestNet.name, - isFailover: true, - isDown: false, - ); - - static NodeModel get firoTestnet => NodeModel( - host: "firo-testnet.stackwallet.com", - port: 50002, - name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.firoTestNet), - useSSL: true, - enabled: true, - coinName: Coin.firoTestNet.name, - isFailover: true, - isDown: false, - ); - - static NodeModel get dogecoinTestnet => NodeModel( - host: "dogecoin-testnet.stackwallet.com", - port: 50022, - name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.dogecoinTestNet), - useSSL: true, - enabled: true, - coinName: Coin.dogecoinTestNet.name, - isFailover: true, - isDown: false, - ); - - static NodeModel get bitcoincashTestnet => NodeModel( - host: "bitcoincash-testnet.stackwallet.com", - port: 60002, - name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.bitcoincashTestnet), - useSSL: true, - enabled: true, - coinName: Coin.bitcoincashTestnet.name, - isFailover: true, - isDown: false, - ); - - static NodeModel get eCash => NodeModel( - host: "ecash.stackwallet.com", - port: 59002, - name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.eCash), - useSSL: true, - enabled: true, - coinName: Coin.eCash.name, - isFailover: true, - isDown: false, - ); - - static NodeModel get peercoinTestNet => NodeModel( - host: "testnet-electrum.peercoinexplorer.net", - port: 50002, - name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.peercoinTestNet), - useSSL: true, - enabled: true, - coinName: Coin.peercoinTestNet.name, - isFailover: true, - isDown: false, - ); - - static NodeModel get stellarTestnet => NodeModel( - host: "https://horizon-testnet.stellar.org/", - port: 50022, - name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.stellarTestnet), - useSSL: true, - enabled: true, - coinName: Coin.stellarTestnet.name, - isFailover: true, - isDown: false, - ); - - static NodeModel getNodeFor(Coin coin) { - switch (coin) { - case Coin.bitcoin: - case Coin.bitcoinFrost: - return bitcoin; - - case Coin.litecoin: - return litecoin; - - case Coin.bitcoincash: - return bitcoincash; - - case Coin.dogecoin: - return dogecoin; - - case Coin.eCash: - return eCash; - - case Coin.epicCash: - return epicCash; - - case Coin.ethereum: - return ethereum; - - case Coin.firo: - return firo; - - case Coin.monero: - return monero; - - case Coin.wownero: - return wownero; - - case Coin.namecoin: - return namecoin; - - case Coin.particl: - return particl; - - case Coin.peercoin: - return peercoin; - - case Coin.peercoinTestNet: - return peercoinTestNet; - - case Coin.solana: - return solana; - - case Coin.stellar: - return stellar; - - case Coin.nano: - return nano; - - case Coin.banano: - return banano; - - case Coin.tezos: - return tezos; - - case Coin.bitcoinTestNet: - case Coin.bitcoinFrostTestNet: - return bitcoinTestnet; - - case Coin.litecoinTestNet: - return litecoinTestNet; - - case Coin.bitcoincashTestnet: - return bitcoincashTestnet; - - case Coin.firoTestNet: - return firoTestnet; - - case Coin.dogecoinTestNet: - return dogecoinTestnet; - - case Coin.stellarTestnet: - return stellarTestnet; - } - } } diff --git a/lib/utilities/enums/coin_enum.dart b/lib/utilities/enums/coin_enum.dart deleted file mode 100644 index 903054b09..000000000 --- a/lib/utilities/enums/coin_enum.dart +++ /dev/null @@ -1,632 +0,0 @@ -/* - * This file is part of Stack Wallet. - * - * Copyright (c) 2023 Cypher Stack - * All Rights Reserved. - * The code is distributed under GPLv3 license, see LICENSE file for details. - * Generated by Cypher Stack on 2023-05-26 - * - */ - -import 'package:stackwallet/models/isar/models/blockchain_data/address.dart'; -import 'package:stackwallet/utilities/constants.dart'; - -enum Coin { - bitcoin, - monero, - banano, - bitcoincash, - bitcoinFrost, - dogecoin, - eCash, - epicCash, - ethereum, - firo, - litecoin, - namecoin, - nano, - particl, - peercoin, - solana, - stellar, - tezos, - wownero, - - /// - - /// - /// - - bitcoinTestNet, - bitcoincashTestnet, - bitcoinFrostTestNet, - dogecoinTestNet, - firoTestNet, - litecoinTestNet, - peercoinTestNet, - stellarTestnet, -} - -extension CoinExt on Coin { - String get prettyName { - switch (this) { - case Coin.bitcoin: - return "Bitcoin"; - case Coin.bitcoinFrost: - return "Bitcoin Frost"; - case Coin.litecoin: - return "Litecoin"; - case Coin.bitcoincash: - return "Bitcoin Cash"; - case Coin.dogecoin: - return "Dogecoin"; - case Coin.epicCash: - return "Epic Cash"; - case Coin.eCash: - return "eCash"; - case Coin.ethereum: - return "Ethereum"; - case Coin.firo: - return "Firo"; - case Coin.monero: - return "Monero"; - case Coin.particl: - return "Particl"; - case Coin.peercoin: - return "Peercoin"; - case Coin.solana: - return "Solana"; - case Coin.stellar: - return "Stellar"; - case Coin.tezos: - return "Tezos"; - case Coin.wownero: - return "Wownero"; - case Coin.namecoin: - return "Namecoin"; - case Coin.nano: - return "Nano"; - case Coin.banano: - return "Banano"; - case Coin.bitcoinTestNet: - return "tBitcoin"; - case Coin.bitcoinFrostTestNet: - return "tBitcoin Frost"; - case Coin.litecoinTestNet: - return "tLitecoin"; - case Coin.bitcoincashTestnet: - return "tBitcoin Cash"; - case Coin.firoTestNet: - return "tFiro"; - case Coin.dogecoinTestNet: - return "tDogecoin"; - case Coin.peercoinTestNet: - return "tPeercoin"; - case Coin.stellarTestnet: - return "tStellar"; - } - } - - String get ticker { - switch (this) { - case Coin.bitcoin: - case Coin.bitcoinFrost: - return "BTC"; - case Coin.litecoin: - return "LTC"; - case Coin.bitcoincash: - return "BCH"; - case Coin.dogecoin: - return "DOGE"; - case Coin.epicCash: - return "EPIC"; - case Coin.ethereum: - return "ETH"; - case Coin.eCash: - return "XEC"; - case Coin.firo: - return "FIRO"; - case Coin.monero: - return "XMR"; - case Coin.particl: - return "PART"; - case Coin.peercoin: - return "PPC"; - case Coin.solana: - return "SOL"; - case Coin.stellar: - return "XLM"; - case Coin.tezos: - return "XTZ"; - case Coin.wownero: - return "WOW"; - case Coin.namecoin: - return "NMC"; - case Coin.nano: - return "XNO"; - case Coin.banano: - return "BAN"; - case Coin.bitcoinTestNet: - case Coin.bitcoinFrostTestNet: - return "tBTC"; - case Coin.litecoinTestNet: - return "tLTC"; - case Coin.bitcoincashTestnet: - return "tBCH"; - case Coin.firoTestNet: - return "tFIRO"; - case Coin.dogecoinTestNet: - return "tDOGE"; - case Coin.peercoinTestNet: - return "tPPC"; - case Coin.stellarTestnet: - return "tXLM"; - } - } - - String get uriScheme { - switch (this) { - case Coin.bitcoin: - case Coin.bitcoinFrost: - return "bitcoin"; - case Coin.litecoin: - return "litecoin"; - case Coin.bitcoincash: - return "bitcoincash"; - case Coin.dogecoin: - return "dogecoin"; - case Coin.epicCash: - // TODO: is this actually the right one? - return "epic"; - case Coin.ethereum: - return "ethereum"; - case Coin.eCash: - return "ecash"; - case Coin.firo: - return "firo"; - case Coin.monero: - return "monero"; - case Coin.particl: - return "particl"; - case Coin.peercoin: - return "peercoin"; - case Coin.solana: - return "solana"; - case Coin.stellar: - return "stellar"; - case Coin.tezos: - return "tezos"; - case Coin.wownero: - return "wownero"; - case Coin.namecoin: - return "namecoin"; - case Coin.nano: - return "nano"; - case Coin.banano: - return "ban"; - case Coin.bitcoinTestNet: - case Coin.bitcoinFrostTestNet: - return "bitcoin"; - case Coin.litecoinTestNet: - return "litecoin"; - case Coin.bitcoincashTestnet: - return "bchtest"; - case Coin.firoTestNet: - return "firo"; - case Coin.dogecoinTestNet: - return "dogecoin"; - case Coin.peercoinTestNet: - return "peercoin"; - case Coin.stellarTestnet: - return "stellar"; - } - } - - bool get hasMnemonicPassphraseSupport { - switch (this) { - case Coin.bitcoin: - case Coin.bitcoinTestNet: - case Coin.litecoin: - case Coin.litecoinTestNet: - case Coin.bitcoincash: - case Coin.bitcoincashTestnet: - case Coin.dogecoin: - case Coin.dogecoinTestNet: - case Coin.firo: - case Coin.firoTestNet: - case Coin.namecoin: - case Coin.particl: - case Coin.peercoin: - case Coin.peercoinTestNet: - case Coin.ethereum: - case Coin.eCash: - case Coin.stellar: - case Coin.stellarTestnet: - return true; - - case Coin.bitcoinFrost: - case Coin.bitcoinFrostTestNet: - case Coin.epicCash: - case Coin.monero: - case Coin.wownero: - case Coin.nano: - case Coin.banano: - case Coin.tezos: - case Coin.solana: - return false; - } - } - - bool get hasBuySupport { - switch (this) { - case Coin.bitcoin: - case Coin.litecoin: - case Coin.bitcoincash: - case Coin.dogecoin: - case Coin.ethereum: - return true; - - case Coin.bitcoinFrost: - case Coin.bitcoinFrostTestNet: - case Coin.firo: - case Coin.namecoin: - case Coin.particl: - case Coin.peercoin: - case Coin.peercoinTestNet: - case Coin.eCash: - case Coin.epicCash: - case Coin.monero: - case Coin.tezos: - case Coin.wownero: - case Coin.dogecoinTestNet: - case Coin.bitcoinTestNet: - case Coin.litecoinTestNet: - case Coin.bitcoincashTestnet: - case Coin.firoTestNet: - case Coin.nano: - case Coin.banano: - case Coin.solana: - case Coin.stellar: - case Coin.stellarTestnet: - return false; - } - } - - bool get isTestNet { - switch (this) { - case Coin.bitcoin: - case Coin.bitcoinFrost: - case Coin.litecoin: - case Coin.bitcoincash: - case Coin.dogecoin: - case Coin.firo: - case Coin.namecoin: - case Coin.particl: - case Coin.peercoin: - case Coin.epicCash: - case Coin.ethereum: - case Coin.monero: - case Coin.tezos: - case Coin.wownero: - case Coin.nano: - case Coin.banano: - case Coin.eCash: - case Coin.stellar: - case Coin.solana: - return false; - - case Coin.dogecoinTestNet: - case Coin.bitcoinTestNet: - case Coin.bitcoinFrostTestNet: - case Coin.litecoinTestNet: - case Coin.bitcoincashTestnet: - case Coin.firoTestNet: - case Coin.peercoinTestNet: - case Coin.stellarTestnet: - return true; - } - } - - bool get isFrost { - switch (this) { - case Coin.bitcoinFrost: - case Coin.bitcoinFrostTestNet: - return true; - - default: - return false; - } - } - - Coin get mainNetVersion { - switch (this) { - case Coin.bitcoin: - case Coin.bitcoinFrost: - case Coin.litecoin: - case Coin.bitcoincash: - case Coin.dogecoin: - case Coin.firo: - case Coin.namecoin: - case Coin.particl: - case Coin.peercoin: - case Coin.epicCash: - case Coin.ethereum: - case Coin.monero: - case Coin.tezos: - case Coin.wownero: - case Coin.nano: - case Coin.banano: - case Coin.eCash: - case Coin.stellar: - case Coin.solana: - return this; - - case Coin.dogecoinTestNet: - return Coin.dogecoin; - - case Coin.bitcoinTestNet: - return Coin.bitcoin; - - case Coin.bitcoinFrostTestNet: - return Coin.bitcoinFrost; - - case Coin.litecoinTestNet: - return Coin.litecoin; - - case Coin.bitcoincashTestnet: - return Coin.bitcoincash; - - case Coin.firoTestNet: - return Coin.firo; - - case Coin.peercoinTestNet: - return Coin.peercoin; - - case Coin.stellarTestnet: - return Coin.stellar; - } - } - - int get decimals => Constants.decimalPlacesForCoin(this); - - // Note: this must relate to DerivePathType for certain coins! - AddressType get primaryAddressType { - switch (this) { - case Coin.bitcoin: - case Coin.bitcoinTestNet: - case Coin.litecoin: - case Coin.litecoinTestNet: - case Coin.namecoin: - case Coin.particl: - case Coin.peercoin: - case Coin.peercoinTestNet: - return AddressType.p2wpkh; - - case Coin.bitcoinFrost: - case Coin.bitcoinFrostTestNet: - return AddressType.frostMS; - - case Coin.eCash: - case Coin.bitcoincash: - case Coin.bitcoincashTestnet: - case Coin.dogecoin: - case Coin.firo: - case Coin.firoTestNet: - case Coin.dogecoinTestNet: - return AddressType.p2pkh; - - case Coin.monero: - case Coin.wownero: - return AddressType.cryptonote; - - case Coin.epicCash: - return AddressType.mimbleWimble; - - case Coin.ethereum: - return AddressType.ethereum; - - case Coin.tezos: - return AddressType.tezos; - - case Coin.nano: - return AddressType.nano; - - case Coin.banano: - return AddressType.banano; - - case Coin.stellar: - case Coin.stellarTestnet: - return AddressType.stellar; - - case Coin.solana: - return AddressType.solana; - } - } -} - -Coin coinFromPrettyName(String name) { - switch (name) { - case "Bitcoin": - case "bitcoin": - return Coin.bitcoin; - - case "Litecoin": - case "litecoin": - return Coin.litecoin; - - case "Bitcoincash": - case "bitcoincash": - case "Bitcoin Cash": - return Coin.bitcoincash; - - case "Dogecoin": - case "dogecoin": - return Coin.dogecoin; - - case "Epic Cash": - case "epicCash": - return Coin.epicCash; - - case "Ethereum": - case "ethereum": - return Coin.ethereum; - - case "Firo": - case "firo": - return Coin.firo; - - case "E-Cash": - case "ecash": - case "eCash": - return Coin.eCash; - - case "Monero": - case "monero": - return Coin.monero; - - case "Particl": - case "particl": - return Coin.particl; - - case "Peercoin": - case "peercoin": - return Coin.peercoin; - - case "tPeercoin": - case "Peercoin Testnet": - case "peercoinTestNet": - return Coin.peercoinTestNet; - - case "Solana": - case "solana": - return Coin.solana; - - case "Stellar": - case "stellar": - return Coin.stellar; - - case "Tezos": - case "tezos": - return Coin.tezos; - - case "Namecoin": - case "namecoin": - return Coin.namecoin; - - case "Bitcoin Testnet": - case "tBitcoin": - case "bitcoinTestNet": - return Coin.bitcoinTestNet; - - case "Litecoin Testnet": - case "tlitecoin": - case "litecoinTestNet": - case "tLitecoin": - return Coin.litecoinTestNet; - - case "Bitcoincash Testnet": - case "tBitcoin Cash": - case "Bitcoin Cash Testnet": - case "bitcoincashTestnet": - return Coin.bitcoincashTestnet; - - case "Firo Testnet": - case "tFiro": - case "firoTestNet": - return Coin.firoTestNet; - - case "Dogecoin Testnet": - case "tDogecoin": - case "dogecoinTestNet": - return Coin.dogecoinTestNet; - - case "Wownero": - case "tWownero": - case "wownero": - return Coin.wownero; - - case "Nano": - case "nano": - return Coin.nano; - - case "Banano": - case "banano": - return Coin.banano; - - case "Stellar Testnet": - case "stellarTestnet": - case "stellarTestNet": - case "tStellar": - return Coin.stellarTestnet; - - case "Bitcoin Frost": - case "bitcoinFrost": - return Coin.bitcoinFrost; - - case "Bitcoin Frost Testnet": - case "tBitcoin Frost": - case "bitcoinFrostTestNet": - return Coin.bitcoinFrostTestNet; - - default: - throw ArgumentError.value( - name, - "name", - "No Coin enum value with that prettyName", - ); - } -} - -Coin coinFromTickerCaseInsensitive(String ticker) { - switch (ticker.toLowerCase()) { - case "btc": - return Coin.bitcoin; - case "ltc": - return Coin.litecoin; - case "bch": - return Coin.bitcoincash; - case "doge": - return Coin.dogecoin; - case "epic": - return Coin.epicCash; - case "xec": - return Coin.eCash; - case "eth": - return Coin.ethereum; - case "firo": - return Coin.firo; - case "xmr": - return Coin.monero; - case "nmc": - return Coin.namecoin; - case "part": - return Coin.particl; - case "sol": - return Coin.solana; - case "xlm": - return Coin.stellar; - case "xtz": - return Coin.tezos; - case "tltc": - return Coin.litecoinTestNet; - case "tbtc": - return Coin.bitcoinTestNet; - case "tbch": - return Coin.bitcoincashTestnet; - case "tfiro": - return Coin.firoTestNet; - case "tdoge": - return Coin.dogecoinTestNet; - case "wow": - return Coin.wownero; - case "xno": - return Coin.nano; - case "ban": - return Coin.banano; - case "txlm": - return Coin.stellarTestnet; - default: - throw ArgumentError.value( - ticker, "name", "No Coin enum value with that ticker"); - } -} diff --git a/lib/utilities/enums/derive_path_type_enum.dart b/lib/utilities/enums/derive_path_type_enum.dart index 4dcaef022..d17a6584a 100644 --- a/lib/utilities/enums/derive_path_type_enum.dart +++ b/lib/utilities/enums/derive_path_type_enum.dart @@ -9,7 +9,6 @@ */ import 'package:stackwallet/models/isar/models/blockchain_data/address.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; enum DerivePathType { bip44, @@ -45,49 +44,3 @@ enum DerivePathType { } } } - -extension DerivePathTypeExt on DerivePathType { - static DerivePathType primaryFor(Coin coin) { - switch (coin) { - case Coin.bitcoincash: - case Coin.bitcoincashTestnet: - case Coin.dogecoin: - case Coin.dogecoinTestNet: - case Coin.firo: - case Coin.firoTestNet: - return DerivePathType.bip44; - - case Coin.bitcoin: - case Coin.bitcoinTestNet: - case Coin.litecoin: - case Coin.litecoinTestNet: - case Coin.namecoin: - case Coin.particl: - case Coin.peercoin: - case Coin.peercoinTestNet: - return DerivePathType.bip84; - - case Coin.eCash: - return DerivePathType.eCash44; - - case Coin.ethereum: // TODO: do we need something here? - return DerivePathType.eth; - - case Coin.solana: - return DerivePathType.solana; - - case Coin.bitcoinFrost: - case Coin.bitcoinFrostTestNet: - case Coin.epicCash: - case Coin.monero: - case Coin.wownero: - case Coin.nano: - case Coin.banano: - case Coin.stellar: - case Coin.stellarTestnet: - case Coin.tezos: // TODO: Is this true? - throw UnsupportedError( - "$coin does not use bitcoin style derivation paths"); - } - } -} diff --git a/lib/utilities/eth_commons.dart b/lib/utilities/eth_commons.dart index f6561c8d5..f2c802111 100644 --- a/lib/utilities/eth_commons.dart +++ b/lib/utilities/eth_commons.dart @@ -12,8 +12,8 @@ import 'package:bip32/bip32.dart' as bip32; import 'package:bip39/bip39.dart' as bip39; import 'package:decimal/decimal.dart'; import "package:hex/hex.dart"; -import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/ethereum.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; class GasTracker { final Decimal average; @@ -37,7 +37,8 @@ class GasTracker { }); factory GasTracker.fromJson(Map<String, dynamic> json) { - final targetTime = Constants.targetBlockTimeInSeconds(Coin.ethereum); + final targetTime = + Ethereum(CryptoCurrencyNetwork.main).targetBlockTimeSeconds; return GasTracker( fast: Decimal.parse(json["FastGasPrice"].toString()), average: Decimal.parse(json["ProposeGasPrice"].toString()), diff --git a/lib/utilities/prefs.dart b/lib/utilities/prefs.dart index 07726bdf1..74453c50c 100644 --- a/lib/utilities/prefs.dart +++ b/lib/utilities/prefs.dart @@ -14,12 +14,13 @@ import 'package:flutter/cupertino.dart'; import 'package:stackwallet/db/hive/db.dart'; import 'package:stackwallet/services/event_bus/events/global/tor_status_changed_event.dart'; import 'package:stackwallet/services/event_bus/global_event_bus.dart'; +import 'package:stackwallet/supported_coins.dart'; import 'package:stackwallet/utilities/amount/amount_unit.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/backup_frequency_type.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/languages_enum.dart'; import 'package:stackwallet/utilities/enums/sync_type_enum.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/cash_fusion_interface.dart'; import 'package:uuid/uuid.dart'; @@ -847,15 +848,17 @@ class Prefs extends ChangeNotifier { // coin amount unit settings - final Map<Coin, AmountUnit> _amountUnits = {}; + final Map<CryptoCurrency, AmountUnit> _amountUnits = {}; - AmountUnit amountUnit(Coin coin) => _amountUnits[coin] ?? AmountUnit.normal; + AmountUnit amountUnit(CryptoCurrency coin) => + _amountUnits[coin] ?? AmountUnit.normal; - void updateAmountUnit({required Coin coin, required AmountUnit amountUnit}) { + void updateAmountUnit( + {required CryptoCurrency coin, required AmountUnit amountUnit}) { if (this.amountUnit(coin) != amountUnit) { DB.instance.put<dynamic>( boxName: DB.boxNamePrefs, - key: "amountUnitFor${coin.name}", + key: "amountUnitFor${coin.identifier}", value: amountUnit.index, ); _amountUnits[coin] = amountUnit; @@ -864,10 +867,10 @@ class Prefs extends ChangeNotifier { } Future<void> _setAmountUnits() async { - for (final coin in Coin.values) { + for (final coin in SupportedCoins.cryptocurrencies) { final unitIndex = await DB.instance.get<dynamic>( boxName: DB.boxNamePrefs, - key: "amountUnitFor${coin.name}", + key: "amountUnitFor${coin.identifier}", ) as int? ?? 0; // 0 is "normal" _amountUnits[coin] = AmountUnit.values[unitIndex]; @@ -876,31 +879,35 @@ class Prefs extends ChangeNotifier { // coin precision setting (max decimal places to show) - final Map<Coin, int> _amountDecimals = {}; + final Map<String, int> _amountDecimals = {}; - int maxDecimals(Coin coin) => _amountDecimals[coin] ?? coin.decimals; + int maxDecimals(CryptoCurrency coin) => + _amountDecimals[coin.identifier] ?? coin.fractionDigits; - void updateMaxDecimals({required Coin coin, required int maxDecimals}) { + void updateMaxDecimals({ + required CryptoCurrency coin, + required int maxDecimals, + }) { if (this.maxDecimals(coin) != maxDecimals) { DB.instance.put<dynamic>( boxName: DB.boxNamePrefs, - key: "maxDecimalsFor${coin.name}", + key: "maxDecimalsFor${coin.identifier}", value: maxDecimals, ); - _amountDecimals[coin] = maxDecimals; + _amountDecimals[coin.identifier] = maxDecimals; notifyListeners(); } } Future<void> _setMaxDecimals() async { - for (final coin in Coin.values) { + for (final coin in SupportedCoins.cryptocurrencies) { final decimals = await DB.instance.get<dynamic>( boxName: DB.boxNamePrefs, - key: "maxDecimalsFor${coin.name}", + key: "maxDecimalsFor${coin.identifier}", ) as int? ?? - (coin.decimals > 18 ? 18 : coin.decimals); + (coin.fractionDigits > 18 ? 18 : coin.fractionDigits); // use some sane max rather than up to 30 that nano uses - _amountDecimals[coin] = decimals; + _amountDecimals[coin.identifier] = decimals; } } @@ -938,22 +945,23 @@ class Prefs extends ChangeNotifier { // fusion server info - Map<Coin, FusionInfo> _fusionServerInfo = {}; + Map<String, FusionInfo> _fusionServerInfo = {}; - FusionInfo getFusionServerInfo(Coin coin) { - return _fusionServerInfo[coin] ?? kFusionServerInfoDefaults[coin]!; + FusionInfo getFusionServerInfo(CryptoCurrency coin) { + return _fusionServerInfo[coin.identifier] ?? + kFusionServerInfoDefaults[coin.identifier]!; } - void setFusionServerInfo(Coin coin, FusionInfo fusionServerInfo) { - if (_fusionServerInfo[coin] != fusionServerInfo) { - _fusionServerInfo[coin] = fusionServerInfo; + void setFusionServerInfo(CryptoCurrency coin, FusionInfo fusionServerInfo) { + if (_fusionServerInfo[coin.identifier] != fusionServerInfo) { + _fusionServerInfo[coin.identifier] = fusionServerInfo; DB.instance.put<dynamic>( boxName: DB.boxNamePrefs, key: "fusionServerInfoMap", value: _fusionServerInfo.map( (key, value) => MapEntry( - key.name, + key, value.toJsonString(), ), ), @@ -962,7 +970,7 @@ class Prefs extends ChangeNotifier { } } - Future<Map<Coin, FusionInfo>> _getFusionServerInfo() async { + Future<Map<String, FusionInfo>> _getFusionServerInfo() async { final map = await DB.instance.get<dynamic>( boxName: DB.boxNamePrefs, key: "fusionServerInfoMap", @@ -974,14 +982,14 @@ class Prefs extends ChangeNotifier { final actualMap = Map<String, String>.from(map).map( (key, value) => MapEntry( - coinFromPrettyName(key), + key, FusionInfo.fromJsonString(value), ), ); // legacy bch check - if (actualMap[Coin.bitcoincash] == null || - actualMap[Coin.bitcoincashTestnet] == null) { + if (actualMap["bitcoincash"] == null || + actualMap["bitcoincashTestnet"] == null) { final saved = await DB.instance.get<dynamic>( boxName: DB.boxNamePrefs, key: "fusionServerInfo", @@ -989,15 +997,15 @@ class Prefs extends ChangeNotifier { if (saved != null) { final bchInfo = FusionInfo.fromJsonString(saved); - actualMap[Coin.bitcoincash] = bchInfo; - actualMap[Coin.bitcoincashTestnet] = bchInfo; + actualMap["bitcoincash"] = bchInfo; + actualMap["bitcoincashTestnet"] = bchInfo; unawaited( DB.instance.put<dynamic>( boxName: DB.boxNamePrefs, key: "fusionServerInfoMap", value: actualMap.map( (key, value) => MapEntry( - key.name, + key, value.toJsonString(), ), ), diff --git a/lib/utilities/test_node_connection.dart b/lib/utilities/test_node_connection.dart new file mode 100644 index 000000000..2113766b1 --- /dev/null +++ b/lib/utilities/test_node_connection.dart @@ -0,0 +1,198 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:solana/solana.dart'; +import 'package:stackwallet/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart'; +import 'package:stackwallet/providers/global/prefs_provider.dart'; +import 'package:stackwallet/services/tor_service.dart'; +import 'package:stackwallet/utilities/connection_check/electrum_connection_check.dart'; +import 'package:stackwallet/utilities/logger.dart'; +import 'package:stackwallet/utilities/test_epic_box_connection.dart'; +import 'package:stackwallet/utilities/test_eth_node_connection.dart'; +import 'package:stackwallet/utilities/test_monero_node_connection.dart'; +import 'package:stackwallet/utilities/test_stellar_node_connection.dart'; +import 'package:stackwallet/wallets/api/tezos/tezos_rpc_api.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/bitcoin_frost.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/epiccash.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/ethereum.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/solana.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/stellar.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/tezos.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; +import 'package:stackwallet/wallets/crypto_currency/interfaces/electrumx_currency_interface.dart'; +import 'package:stackwallet/wallets/crypto_currency/intermediate/cryptonote_currency.dart'; +import 'package:stackwallet/wallets/crypto_currency/intermediate/nano_currency.dart'; + +Future<bool> _xmrHelper( + NodeFormData nodeFormData, + BuildContext context, + void Function(NodeFormData)? onSuccess, +) async { + final data = nodeFormData; + final url = data.host!; + final port = data.port; + + final uri = Uri.parse(url); + + final String path = uri.path.isEmpty ? "/json_rpc" : uri.path; + + final uriString = "${uri.scheme}://${uri.host}:${port ?? 0}$path"; + + final response = await testMoneroNodeConnection( + Uri.parse(uriString), + false, + ); + + if (response.cert != null) { + if (context.mounted) { + final shouldAllowBadCert = await showBadX509CertificateDialog( + response.cert!, + response.url!, + response.port!, + context, + ); + + if (shouldAllowBadCert) { + final response = + await testMoneroNodeConnection(Uri.parse(uriString), true); + onSuccess?.call(data..host = url); + return response.success; + } + } + } else { + onSuccess?.call(data..host = url); + return response.success; + } + + return false; +} + +// TODO: probably pull this into each coin's functionality otherwise updating this separately will get irritating +Future<bool> testNodeConnection({ + required BuildContext context, + required NodeFormData nodeFormData, + required CryptoCurrency cryptoCurrency, + required WidgetRef ref, + void Function(NodeFormData)? onSuccess, +}) async { + final formData = nodeFormData; + + bool testPassed = false; + + switch (cryptoCurrency) { + case Epiccash(): + try { + final data = await testEpicNodeConnection(formData); + + if (data != null) { + testPassed = true; + onSuccess?.call(data); + } + } catch (e, s) { + Logging.instance.log("$e\n$s", level: LogLevel.Warning); + } + break; + + case CryptonoteCurrency(): + try { + final url = formData.host!; + final uri = Uri.tryParse(url); + if (uri != null) { + if (!uri.hasScheme) { + // try https first + testPassed = await _xmrHelper( + formData + ..host = "https://$url" + ..useSSL = true, + context, + onSuccess, + ); + + if (testPassed == false) { + // try http + testPassed = await _xmrHelper( + formData + ..host = "http://$url" + ..useSSL = false, + context, + onSuccess, + ); + } + } else { + testPassed = await _xmrHelper( + formData + ..host = url + ..useSSL = true, + context, + onSuccess, + ); + } + } + } catch (e, s) { + Logging.instance.log("$e\n$s", level: LogLevel.Warning); + } + + break; + + case ElectrumXCurrencyInterface(): + case BitcoinFrost(): + try { + testPassed = await checkElectrumServer( + host: formData.host!, + port: formData.port!, + useSSL: formData.useSSL!, + overridePrefs: ref.read(prefsChangeNotifierProvider), + overrideTorService: ref.read(pTorService), + ); + } catch (_) { + testPassed = false; + } + + break; + + case Ethereum(): + try { + testPassed = await testEthNodeConnection(formData.host!); + } catch (_) { + testPassed = false; + } + break; + + case Stellar(): + try { + testPassed = + await testStellarNodeConnection(formData.host!, formData.port!); + } catch (_) {} + break; + + case NanoCurrency(): + //TODO: check network/node + throw UnimplementedError(); + + case Tezos(): + try { + testPassed = await TezosRpcAPI.testNetworkConnection( + nodeInfo: (host: formData.host!, port: formData.port!), + ); + } catch (_) {} + break; + + case Solana(): + try { + RpcClient rpcClient; + if (formData.host!.startsWith("http") || + formData.host!.startsWith("https")) { + rpcClient = RpcClient("${formData.host}:${formData.port}"); + } else { + rpcClient = RpcClient("http://${formData.host}:${formData.port}"); + } + await rpcClient.getEpochInfo().then((value) => testPassed = true); + } catch (_) { + testPassed = false; + } + break; + } + + return testPassed; +} diff --git a/lib/wallets/crypto_currency/coins/banano.dart b/lib/wallets/crypto_currency/coins/banano.dart index dfae1b78c..c2cb52345 100644 --- a/lib/wallets/crypto_currency/coins/banano.dart +++ b/lib/wallets/crypto_currency/coins/banano.dart @@ -1,7 +1,8 @@ import 'package:nanodart/nanodart.dart'; +import 'package:stackwallet/models/isar/models/blockchain_data/address.dart'; import 'package:stackwallet/models/node_model.dart'; import 'package:stackwallet/utilities/default_nodes.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/crypto_currency/intermediate/nano_currency.dart'; @@ -9,15 +10,50 @@ class Banano extends NanoCurrency { Banano(super.network) { switch (network) { case CryptoCurrencyNetwork.main: - coin = Coin.banano; + _id = "banano"; + _idMain = "banano"; + _name = "Banano"; + _uriScheme = "ban"; + _ticker = "BAN"; default: throw Exception("Unsupported network: $network"); } } + late final String _id; + @override + String get identifier => _id; + + late final String _idMain; + @override + String get mainNetId => _idMain; + + late final String _name; + @override + String get prettyName => _name; + + late final String _uriScheme; + @override + String get uriScheme => _uriScheme; + + late final String _ticker; + @override + String get ticker => _ticker; + + @override + int get fractionDigits => 29; + + @override + BigInt get satsPerCoin => BigInt.parse( + "100000000000000000000000000000", + ); // 1*10^29 + @override int get minConfirms => 1; + @override + AddressType get primaryAddressType => AddressType.banano; + @override String get defaultRepresentative => "ban_1ka1ium4pfue3uxtntqsrib8mumxgazsjf58gidh1xeo5te3whsq8z476goo"; @@ -33,10 +69,10 @@ class Banano extends NanoCurrency { host: "https://kaliumapi.appditto.com/api", port: 443, name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.banano), + id: DefaultNodes.buildId(this), useSSL: true, enabled: true, - coinName: Coin.banano.name, + coinName: identifier, isFailover: true, isDown: false, ); @@ -47,10 +83,19 @@ class Banano extends NanoCurrency { } @override - bool operator ==(Object other) { - return other is Banano && other.network == network; + Uri defaultBlockExplorer(String txid) { + switch (network) { + case CryptoCurrencyNetwork.main: + return Uri.parse("https://www.bananolooker.com/block/$txid"); + default: + throw Exception( + "Unsupported network for defaultBlockExplorer(): $network", + ); + } } @override - int get hashCode => Object.hash(Banano, network); + DerivePathType get primaryDerivePathType => 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 e0126ede1..e989e51e5 100644 --- a/lib/wallets/crypto_currency/coins/bitcoin.dart +++ b/lib/wallets/crypto_currency/coins/bitcoin.dart @@ -3,24 +3,51 @@ import 'package:stackwallet/models/isar/models/blockchain_data/address.dart'; import 'package:stackwallet/models/node_model.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/default_nodes.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; +import 'package:stackwallet/wallets/crypto_currency/interfaces/electrumx_currency_interface.dart'; import 'package:stackwallet/wallets/crypto_currency/interfaces/paynym_currency_interface.dart'; import 'package:stackwallet/wallets/crypto_currency/intermediate/bip39_hd_currency.dart'; -class Bitcoin extends Bip39HDCurrency with PaynymCurrencyInterface { +class Bitcoin extends Bip39HDCurrency + with ElectrumXCurrencyInterface, PaynymCurrencyInterface { Bitcoin(super.network) { + _idMain = "bitcoin"; + _uriScheme = "bitcoin"; switch (network) { case CryptoCurrencyNetwork.main: - coin = Coin.bitcoin; + _id = _idMain; + _name = "Bitcoin"; + _ticker = "BTC"; case CryptoCurrencyNetwork.test: - coin = Coin.bitcoinTestNet; + _id = "bitcoinTestNet"; + _name = "tBitcoin"; + _ticker = "tBTC"; default: throw Exception("Unsupported network: $network"); } } + late final String _id; + @override + String get identifier => _id; + + late final String _idMain; + @override + String get mainNetId => _idMain; + + late final String _name; + @override + String get prettyName => _name; + + late final String _uriScheme; + @override + String get uriScheme => _uriScheme; + + late final String _ticker; + @override + String get ticker => _ticker; + @override // change this to change the number of confirms a tx needs in order to show as confirmed int get minConfirms => 1; @@ -194,10 +221,30 @@ class Bitcoin extends Bip39HDCurrency with PaynymCurrencyInterface { NodeModel get defaultNode { switch (network) { case CryptoCurrencyNetwork.main: - return DefaultNodes.bitcoin; + return NodeModel( + host: "bitcoin.stackwallet.com", + port: 50002, + name: DefaultNodes.defaultName, + id: DefaultNodes.buildId(this), + useSSL: true, + enabled: true, + coinName: identifier, + isFailover: true, + isDown: false, + ); case CryptoCurrencyNetwork.test: - return DefaultNodes.bitcoinTestnet; + return NodeModel( + host: "bitcoin-testnet.stackwallet.com", + port: 51002, + name: DefaultNodes.defaultName, + id: DefaultNodes.buildId(this), + useSSL: true, + enabled: true, + coinName: identifier, + isFailover: true, + isDown: false, + ); default: throw UnimplementedError(); @@ -205,10 +252,43 @@ class Bitcoin extends Bip39HDCurrency with PaynymCurrencyInterface { } @override - bool operator ==(Object other) { - return other is Bitcoin && other.network == network; - } + int get defaultSeedPhraseLength => 12; @override - int get hashCode => Object.hash(Bitcoin, network); + int get fractionDigits => 8; + + @override + bool get hasBuySupport => true; + + @override + bool get hasMnemonicPassphraseSupport => true; + + @override + List<int> get possibleMnemonicLengths => [defaultSeedPhraseLength, 24]; + + @override + AddressType get primaryAddressType => AddressType.p2wpkh; + + @override + BigInt get satsPerCoin => BigInt.from(100000000); + + @override + int get targetBlockTimeSeconds => 600; + + @override + DerivePathType get primaryDerivePathType => DerivePathType.bip84; + + @override + Uri defaultBlockExplorer(String txid) { + switch (network) { + case CryptoCurrencyNetwork.main: + return Uri.parse("https://mempool.space/tx/$txid"); + case CryptoCurrencyNetwork.test: + return Uri.parse("https://mempool.space/testnet/tx/$txid"); + default: + throw Exception( + "Unsupported network for defaultBlockExplorer(): $network", + ); + } + } } diff --git a/lib/wallets/crypto_currency/coins/bitcoin_frost.dart b/lib/wallets/crypto_currency/coins/bitcoin_frost.dart index bd5216350..3c7973599 100644 --- a/lib/wallets/crypto_currency/coins/bitcoin_frost.dart +++ b/lib/wallets/crypto_currency/coins/bitcoin_frost.dart @@ -1,25 +1,53 @@ import 'dart:typed_data'; +import 'package:coinlib_flutter/coinlib_flutter.dart' as coinlib; +import 'package:stackwallet/models/isar/models/blockchain_data/address.dart'; import 'package:stackwallet/models/node_model.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/default_nodes.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/crypto_currency/intermediate/bip39_hd_currency.dart'; import 'package:stackwallet/wallets/crypto_currency/intermediate/frost_currency.dart'; class BitcoinFrost extends FrostCurrency { BitcoinFrost(super.network) { + _idMain = "bitcoinFrost"; + _uriScheme = "bitcoin"; switch (network) { case CryptoCurrencyNetwork.main: - coin = Coin.bitcoinFrost; + _id = _idMain; + _name = "Bitcoin Frost"; + _ticker = "BTC"; case CryptoCurrencyNetwork.test: - coin = Coin.bitcoinFrostTestNet; + _id = "bitcoinFrostTestNet"; + _name = "tBitcoin Frost"; + _ticker = "tBTC"; default: throw Exception("Unsupported network: $network"); } } + late final String _id; + @override + String get identifier => _id; + + late final String _idMain; + @override + String get mainNetId => _idMain; + + late final String _name; + @override + String get prettyName => _name; + + late final String _uriScheme; + @override + String get uriScheme => _uriScheme; + + late final String _ticker; + @override + String get ticker => _ticker; + @override int get minConfirms => 1; @@ -30,10 +58,30 @@ class BitcoinFrost extends FrostCurrency { NodeModel get defaultNode { switch (network) { case CryptoCurrencyNetwork.main: - return DefaultNodes.bitcoin; + return NodeModel( + host: "bitcoin.stackwallet.com", + port: 50002, + name: DefaultNodes.defaultName, + id: DefaultNodes.buildId(this), + useSSL: true, + enabled: true, + coinName: identifier, + isFailover: true, + isDown: false, + ); case CryptoCurrencyNetwork.test: - return DefaultNodes.bitcoinTestnet; + return NodeModel( + host: "bitcoin-testnet.stackwallet.com", + port: 51002, + name: DefaultNodes.defaultName, + id: DefaultNodes.buildId(this), + useSSL: true, + enabled: true, + coinName: identifier, + isFailover: true, + isDown: false, + ); default: throw UnimplementedError(); @@ -67,17 +115,89 @@ class BitcoinFrost extends FrostCurrency { } } + coinlib.Network get networkParams { + switch (network) { + case CryptoCurrencyNetwork.main: + return coinlib.Network( + wifPrefix: 0x80, + p2pkhPrefix: 0x00, + p2shPrefix: 0x05, + privHDPrefix: 0x0488ade4, + pubHDPrefix: 0x0488b21e, + bech32Hrp: "bc", + messagePrefix: '\x18Bitcoin Signed Message:\n', + minFee: BigInt.from(1), // TODO [prio=high]. + minOutput: dustLimit.raw, // TODO. + feePerKb: BigInt.from(1), // TODO. + ); + case CryptoCurrencyNetwork.test: + return coinlib.Network( + wifPrefix: 0xef, + p2pkhPrefix: 0x6f, + p2shPrefix: 0xc4, + privHDPrefix: 0x04358394, + pubHDPrefix: 0x043587cf, + bech32Hrp: "tb", + messagePrefix: "\x18Bitcoin Signed Message:\n", + minFee: BigInt.from(1), // TODO [prio=high]. + minOutput: dustLimit.raw, // TODO. + feePerKb: BigInt.from(1), // TODO. + ); + default: + throw Exception("Unsupported network: $network"); + } + } + @override bool validateAddress(String address) { - // TODO: implement validateAddress for frost addresses - return true; + try { + coinlib.Address.fromString(address, networkParams); + return true; + } catch (_) { + return false; + } } @override - bool operator ==(Object other) { - return other is BitcoinFrost && other.network == network; - } + int get defaultSeedPhraseLength => 0; @override - int get hashCode => Object.hash(BitcoinFrost, network); + int get fractionDigits => 8; + + @override + bool get hasBuySupport => false; + + @override + bool get hasMnemonicPassphraseSupport => false; + + @override + List<int> get possibleMnemonicLengths => []; + + @override + AddressType get primaryAddressType => AddressType.frostMS; + + @override + BigInt get satsPerCoin => BigInt.from(100000000); + + @override + int get targetBlockTimeSeconds => 600; + + @override + DerivePathType get primaryDerivePathType => throw UnsupportedError( + "$runtimeType does not use bitcoin style derivation paths", + ); + + @override + Uri defaultBlockExplorer(String txid) { + switch (network) { + case CryptoCurrencyNetwork.main: + return Uri.parse("https://mempool.space/tx/$txid"); + case CryptoCurrencyNetwork.test: + return Uri.parse("https://mempool.space/testnet/tx/$txid"); + default: + throw Exception( + "Unsupported network for defaultBlockExplorer(): $network", + ); + } + } } diff --git a/lib/wallets/crypto_currency/coins/bitcoincash.dart b/lib/wallets/crypto_currency/coins/bitcoincash.dart index 168e0223a..9059e0358 100644 --- a/lib/wallets/crypto_currency/coins/bitcoincash.dart +++ b/lib/wallets/crypto_currency/coins/bitcoincash.dart @@ -8,23 +8,50 @@ import 'package:stackwallet/models/isar/models/blockchain_data/address.dart'; import 'package:stackwallet/models/node_model.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/default_nodes.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; +import 'package:stackwallet/wallets/crypto_currency/interfaces/electrumx_currency_interface.dart'; import 'package:stackwallet/wallets/crypto_currency/intermediate/bip39_hd_currency.dart'; -class Bitcoincash extends Bip39HDCurrency { +class Bitcoincash extends Bip39HDCurrency with ElectrumXCurrencyInterface { Bitcoincash(super.network) { + _idMain = "bitcoincash"; switch (network) { case CryptoCurrencyNetwork.main: - coin = Coin.bitcoincash; + _id = _idMain; + _name = "Bitcoin Cash"; + _ticker = "BCH"; + _uriScheme = "bitcoincash"; case CryptoCurrencyNetwork.test: - coin = Coin.bitcoincashTestnet; + _id = "bitcoincashTestnet"; + _name = "tBitcoin Cash"; + _ticker = "tBCH"; + _uriScheme = "bchtest"; default: throw Exception("Unsupported network: $network"); } } + late final String _id; + @override + String get identifier => _id; + + late final String _idMain; + @override + String get mainNetId => _idMain; + + late final String _name; + @override + String get prettyName => _name; + + late final String _uriScheme; + @override + String get uriScheme => _uriScheme; + + late final String _ticker; + @override + String get ticker => _ticker; + @override int get maxUnusedAddressGap => 50; @override @@ -40,7 +67,7 @@ class Bitcoincash extends Bip39HDCurrency { @override List<DerivePathType> get supportedDerivationPathTypes => [ DerivePathType.bip44, - if (coin != Coin.bitcoincashTestnet) DerivePathType.bch44, + if (network != CryptoCurrencyNetwork.test) DerivePathType.bch44, ]; @override @@ -181,7 +208,7 @@ class Bitcoincash extends Bip39HDCurrency { // 0 for bitcoincash: address scheme, 1 for legacy address final format = bitbox.Address.detectFormat(address); - if (coin == Coin.bitcoincashTestnet) { + if (network == CryptoCurrencyNetwork.test) { return true; } @@ -264,10 +291,10 @@ class Bitcoincash extends Bip39HDCurrency { host: "bitcoincash.stackwallet.com", port: 50002, name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.bitcoincash), + id: DefaultNodes.buildId(this), useSSL: true, enabled: true, - coinName: Coin.bitcoincash.name, + coinName: identifier, isFailover: true, isDown: false, ); @@ -277,10 +304,10 @@ class Bitcoincash extends Bip39HDCurrency { host: "bitcoincash-testnet.stackwallet.com", port: 60002, name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.bitcoincashTestnet), + id: DefaultNodes.buildId(this), useSSL: true, enabled: true, - coinName: Coin.bitcoincashTestnet.name, + coinName: identifier, isFailover: true, isDown: false, ); @@ -291,10 +318,47 @@ class Bitcoincash extends Bip39HDCurrency { } @override - bool operator ==(Object other) { - return other is Bitcoincash && other.network == network; - } + int get defaultSeedPhraseLength => 12; @override - int get hashCode => Object.hash(Bitcoincash, network); + int get fractionDigits => 8; + + @override + bool get hasBuySupport => true; + + @override + bool get hasMnemonicPassphraseSupport => true; + + @override + List<int> get possibleMnemonicLengths => [defaultSeedPhraseLength, 24]; + + @override + AddressType get primaryAddressType => AddressType.p2pkh; + + @override + BigInt get satsPerCoin => BigInt.from(100000000); + + @override + int get targetBlockTimeSeconds => 600; + + @override + DerivePathType get primaryDerivePathType => DerivePathType.bip44; + + @override + Uri defaultBlockExplorer(String txid) { + switch (network) { + case CryptoCurrencyNetwork.main: + return Uri.parse( + "https://blockchair.com/bitcoin-cash/transaction/$txid", + ); + case CryptoCurrencyNetwork.test: + return Uri.parse( + "https://blockexplorer.one/bitcoin-cash/testnet/tx/$txid", + ); + default: + throw Exception( + "Unsupported network for defaultBlockExplorer(): $network", + ); + } + } } diff --git a/lib/wallets/crypto_currency/coins/dogecoin.dart b/lib/wallets/crypto_currency/coins/dogecoin.dart index 26abdaa85..7019df2f6 100644 --- a/lib/wallets/crypto_currency/coins/dogecoin.dart +++ b/lib/wallets/crypto_currency/coins/dogecoin.dart @@ -3,23 +3,49 @@ import 'package:stackwallet/models/isar/models/blockchain_data/address.dart'; import 'package:stackwallet/models/node_model.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/default_nodes.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; +import 'package:stackwallet/wallets/crypto_currency/interfaces/electrumx_currency_interface.dart'; import 'package:stackwallet/wallets/crypto_currency/intermediate/bip39_hd_currency.dart'; -class Dogecoin extends Bip39HDCurrency { +class Dogecoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { Dogecoin(super.network) { + _idMain = "dogecoin"; + _uriScheme = "dogecoin"; switch (network) { case CryptoCurrencyNetwork.main: - coin = Coin.dogecoin; + _id = _idMain; + _name = "Dogecoin"; + _ticker = "DOGE"; case CryptoCurrencyNetwork.test: - coin = Coin.dogecoinTestNet; + _id = "dogecoinTestNet"; + _name = "tDogecoin"; + _ticker = "tDOGE"; default: throw Exception("Unsupported network: $network"); } } + late final String _id; + @override + String get identifier => _id; + + late final String _idMain; + @override + String get mainNetId => _idMain; + + late final String _name; + @override + String get prettyName => _name; + + late final String _uriScheme; + @override + String get uriScheme => _uriScheme; + + late final String _ticker; + @override + String get ticker => _ticker; + @override bool get torSupport => true; @@ -64,7 +90,7 @@ class Dogecoin extends Bip39HDCurrency { @override Amount get dustLimit => Amount( rawValue: BigInt.from(1000000), - fractionDigits: Coin.particl.decimals, + fractionDigits: fractionDigits, ); @override @@ -156,10 +182,10 @@ class Dogecoin extends Bip39HDCurrency { host: "dogecoin.stackwallet.com", port: 50022, name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.dogecoin), + id: DefaultNodes.buildId(this), useSSL: true, enabled: true, - coinName: Coin.dogecoin.name, + coinName: identifier, isFailover: true, isDown: false, ); @@ -169,10 +195,10 @@ class Dogecoin extends Bip39HDCurrency { host: "dogecoin-testnet.stackwallet.com", port: 50022, name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.dogecoinTestNet), + id: DefaultNodes.buildId(this), useSSL: true, enabled: true, - coinName: Coin.dogecoinTestNet.name, + coinName: identifier, isFailover: true, isDown: false, ); @@ -183,10 +209,43 @@ class Dogecoin extends Bip39HDCurrency { } @override - bool operator ==(Object other) { - return other is Dogecoin && other.network == network; - } + int get defaultSeedPhraseLength => 12; @override - int get hashCode => Object.hash(Dogecoin, network); + int get fractionDigits => 8; + + @override + bool get hasBuySupport => true; + + @override + bool get hasMnemonicPassphraseSupport => true; + + @override + List<int> get possibleMnemonicLengths => [defaultSeedPhraseLength, 24]; + + @override + AddressType get primaryAddressType => AddressType.p2pkh; + + @override + BigInt get satsPerCoin => BigInt.from(100000000); + + @override + int get targetBlockTimeSeconds => 60; + + @override + DerivePathType get primaryDerivePathType => DerivePathType.bip44; + + @override + Uri defaultBlockExplorer(String txid) { + switch (network) { + case CryptoCurrencyNetwork.main: + return Uri.parse("https://chain.so/tx/DOGE/$txid"); + case CryptoCurrencyNetwork.test: + return Uri.parse("https://chain.so/tx/DOGETEST/$txid"); + default: + throw Exception( + "Unsupported network for defaultBlockExplorer(): $network", + ); + } + } } diff --git a/lib/wallets/crypto_currency/coins/ecash.dart b/lib/wallets/crypto_currency/coins/ecash.dart index 6c068ed4d..9cec2f9cb 100644 --- a/lib/wallets/crypto_currency/coins/ecash.dart +++ b/lib/wallets/crypto_currency/coins/ecash.dart @@ -8,21 +8,45 @@ import 'package:stackwallet/models/isar/models/blockchain_data/address.dart'; import 'package:stackwallet/models/node_model.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/default_nodes.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; +import 'package:stackwallet/wallets/crypto_currency/interfaces/electrumx_currency_interface.dart'; import 'package:stackwallet/wallets/crypto_currency/intermediate/bip39_hd_currency.dart'; -class Ecash extends Bip39HDCurrency { +class Ecash extends Bip39HDCurrency with ElectrumXCurrencyInterface { Ecash(super.network) { + _idMain = "eCash"; switch (network) { case CryptoCurrencyNetwork.main: - coin = Coin.eCash; + _id = _idMain; + _name = "eCash"; + _ticker = "XEC"; + _uriScheme = "ecash"; default: throw Exception("Unsupported network: $network"); } } + late final String _id; + @override + String get identifier => _id; + + late final String _idMain; + @override + String get mainNetId => _idMain; + + late final String _name; + @override + String get prettyName => _name; + + late final String _uriScheme; + @override + String get uriScheme => _uriScheme; + + late final String _ticker; + @override + String get ticker => _ticker; + @override int get maxUnusedAddressGap => 50; @override @@ -254,13 +278,15 @@ class Ecash extends Bip39HDCurrency { switch (network) { case CryptoCurrencyNetwork.main: return NodeModel( + // host: "ecash.stackwallet.com", + // port: 59002, host: "electrum.bitcoinabc.org", port: 50002, name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.eCash), + id: DefaultNodes.buildId(this), useSSL: true, enabled: true, - coinName: Coin.eCash.name, + coinName: identifier, isFailover: true, isDown: false, ); @@ -271,10 +297,41 @@ class Ecash extends Bip39HDCurrency { } @override - bool operator ==(Object other) { - return other is Ecash && other.network == network; - } + int get defaultSeedPhraseLength => 12; @override - int get hashCode => Object.hash(Ecash, network); + int get fractionDigits => 2; + + @override + bool get hasBuySupport => false; + + @override + bool get hasMnemonicPassphraseSupport => true; + + @override + List<int> get possibleMnemonicLengths => [defaultSeedPhraseLength, 24]; + + @override + AddressType get primaryAddressType => AddressType.p2pkh; + + @override + BigInt get satsPerCoin => BigInt.from(100); + + @override + int get targetBlockTimeSeconds => 600; + + @override + DerivePathType get primaryDerivePathType => DerivePathType.eCash44; + + @override + Uri defaultBlockExplorer(String txid) { + switch (network) { + case CryptoCurrencyNetwork.main: + return Uri.parse("https://explorer.e.cash/tx/$txid"); + default: + throw Exception( + "Unsupported network for defaultBlockExplorer(): $network", + ); + } + } } diff --git a/lib/wallets/crypto_currency/coins/epiccash.dart b/lib/wallets/crypto_currency/coins/epiccash.dart index 49d7a7a7f..4c49bee5e 100644 --- a/lib/wallets/crypto_currency/coins/epiccash.dart +++ b/lib/wallets/crypto_currency/coins/epiccash.dart @@ -1,20 +1,45 @@ import 'package:flutter_libepiccash/lib.dart' as epic; +import 'package:stackwallet/models/isar/models/blockchain_data/address.dart'; import 'package:stackwallet/models/node_model.dart'; import 'package:stackwallet/utilities/default_nodes.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/crypto_currency/intermediate/bip39_currency.dart'; class Epiccash extends Bip39Currency { Epiccash(super.network) { + _idMain = "epicCash"; + _uriScheme = "epic"; // ? switch (network) { case CryptoCurrencyNetwork.main: - coin = Coin.epicCash; + _id = _idMain; + _name = "Epic Cash"; + _ticker = "EPIC"; default: throw Exception("Unsupported network: $network"); } } + late final String _id; + @override + String get identifier => _id; + + late final String _idMain; + @override + String get mainNetId => _idMain; + + late final String _name; + @override + String get prettyName => _name; + + late final String _uriScheme; + @override + String get uriScheme => _uriScheme; + + late final String _ticker; + @override + String get ticker => _ticker; + @override String get genesisHash { return "not used in epiccash"; @@ -45,16 +70,15 @@ class Epiccash extends Bip39Currency { switch (network) { case CryptoCurrencyNetwork.main: return NodeModel( - host: "https://wownero.stackwallet.com", - port: 34568, + host: "http://epiccash.stackwallet.com", + port: 3413, name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.wownero), - useSSL: true, + id: DefaultNodes.buildId(this), + useSSL: false, enabled: true, - coinName: Coin.wownero.name, + coinName: identifier, isFailover: true, isDown: false, - trusted: true, ); default: @@ -63,10 +87,41 @@ class Epiccash extends Bip39Currency { } @override - bool operator ==(Object other) { - return other is Epiccash && other.network == network; - } + int get defaultSeedPhraseLength => 24; @override - int get hashCode => Object.hash(Epiccash, network); + int get fractionDigits => 8; + + @override + bool get hasBuySupport => false; + + @override + bool get hasMnemonicPassphraseSupport => false; + + @override + List<int> get possibleMnemonicLengths => [defaultSeedPhraseLength, 12]; + + @override + AddressType get primaryAddressType => AddressType.mimbleWimble; + + @override + BigInt get satsPerCoin => BigInt.from(100000000); + + @override + int get targetBlockTimeSeconds => 60; + + @override + DerivePathType get primaryDerivePathType => throw UnsupportedError( + "$runtimeType does not use bitcoin style derivation paths", + ); + + @override + Uri defaultBlockExplorer(String txid) { + switch (network) { + default: + throw Exception( + "Unsupported network for defaultBlockExplorer(): $network", + ); + } + } } diff --git a/lib/wallets/crypto_currency/coins/ethereum.dart b/lib/wallets/crypto_currency/coins/ethereum.dart index a9bc81380..5c6c4f0a1 100644 --- a/lib/wallets/crypto_currency/coins/ethereum.dart +++ b/lib/wallets/crypto_currency/coins/ethereum.dart @@ -1,31 +1,66 @@ import 'package:ethereum_addresses/ethereum_addresses.dart'; +import 'package:stackwallet/models/isar/models/blockchain_data/address.dart'; import 'package:stackwallet/models/node_model.dart'; import 'package:stackwallet/utilities/default_nodes.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/crypto_currency/intermediate/bip39_currency.dart'; class Ethereum extends Bip39Currency { Ethereum(super.network) { + _idMain = "ethereum"; + _uriScheme = "ethereum"; switch (network) { case CryptoCurrencyNetwork.main: - coin = Coin.ethereum; + _id = _idMain; + _name = "Ethereum"; + _ticker = "ETH"; default: throw Exception("Unsupported network: $network"); } } + late final String _id; + @override + String get identifier => _id; + + late final String _idMain; + @override + String get mainNetId => _idMain; + + late final String _name; + @override + String get prettyName => _name; + + late final String _uriScheme; + @override + String get uriScheme => _uriScheme; + + late final String _ticker; + @override + String get ticker => _ticker; + int get gasLimit => 21000; @override bool get hasTokenSupport => true; @override - NodeModel get defaultNode => DefaultNodes.ethereum; + NodeModel get defaultNode => NodeModel( + host: "https://eth.stackwallet.com", + port: 443, + name: DefaultNodes.defaultName, + id: DefaultNodes.buildId(this), + useSSL: true, + enabled: true, + coinName: identifier, + isFailover: true, + isDown: false, + ); @override // Not used for eth - String get genesisHash => throw UnimplementedError(); + String get genesisHash => throw UnimplementedError("Not used for eth"); @override int get minConfirms => 3; @@ -36,10 +71,41 @@ class Ethereum extends Bip39Currency { } @override - bool operator ==(Object other) { - return other is Ethereum && other.network == network; - } + int get defaultSeedPhraseLength => 12; @override - int get hashCode => Object.hash(Ethereum, network); + int get fractionDigits => 18; + + @override + bool get hasBuySupport => true; + + @override + bool get hasMnemonicPassphraseSupport => true; + + @override + List<int> get possibleMnemonicLengths => [defaultSeedPhraseLength, 24]; + + @override + AddressType get primaryAddressType => AddressType.ethereum; + + @override + BigInt get satsPerCoin => BigInt.from(1000000000000000000); + + @override + int get targetBlockTimeSeconds => 15; + + @override + DerivePathType get primaryDerivePathType => DerivePathType.eth; + + @override + Uri defaultBlockExplorer(String txid) { + switch (network) { + case CryptoCurrencyNetwork.main: + return Uri.parse("https://etherscan.io/tx/$txid"); + default: + throw Exception( + "Unsupported network for defaultBlockExplorer(): $network", + ); + } + } } diff --git a/lib/wallets/crypto_currency/coins/firo.dart b/lib/wallets/crypto_currency/coins/firo.dart index 36ad7d763..fbad32ec2 100644 --- a/lib/wallets/crypto_currency/coins/firo.dart +++ b/lib/wallets/crypto_currency/coins/firo.dart @@ -3,24 +3,50 @@ import 'package:stackwallet/models/isar/models/blockchain_data/address.dart'; import 'package:stackwallet/models/node_model.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/default_nodes.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; +import 'package:stackwallet/wallets/crypto_currency/interfaces/electrumx_currency_interface.dart'; import 'package:stackwallet/wallets/crypto_currency/intermediate/bip39_hd_currency.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/spark_interface.dart'; -class Firo extends Bip39HDCurrency { +class Firo extends Bip39HDCurrency with ElectrumXCurrencyInterface { Firo(super.network) { + _idMain = "firo"; + _uriScheme = "firo"; switch (network) { case CryptoCurrencyNetwork.main: - coin = Coin.firo; + _id = _idMain; + _name = "Firo"; + _ticker = "FIRO"; case CryptoCurrencyNetwork.test: - coin = Coin.firoTestNet; + _id = "firoTestNet"; + _name = "tFiro"; + _ticker = "tFIRO"; default: throw Exception("Unsupported network: $network"); } } + late final String _id; + @override + String get identifier => _id; + + late final String _idMain; + @override + String get mainNetId => _idMain; + + late final String _name; + @override + String get prettyName => _name; + + late final String _uriScheme; + @override + String get uriScheme => _uriScheme; + + late final String _ticker; + @override + String get ticker => _ticker; + @override int get minConfirms => 1; @@ -161,10 +187,10 @@ class Firo extends Bip39HDCurrency { host: "firo.stackwallet.com", port: 50002, name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.firo), + id: DefaultNodes.buildId(this), useSSL: true, enabled: true, - coinName: Coin.firo.name, + coinName: identifier, isFailover: true, isDown: false, ); @@ -187,10 +213,10 @@ class Firo extends Bip39HDCurrency { host: "95.179.164.13", port: 51002, name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.firoTestNet), + id: DefaultNodes.buildId(this), useSSL: true, enabled: true, - coinName: Coin.firoTestNet.name, + coinName: identifier, isFailover: true, isDown: false, ); @@ -201,10 +227,43 @@ class Firo extends Bip39HDCurrency { } @override - bool operator ==(Object other) { - return other is Firo && other.network == network; - } + int get defaultSeedPhraseLength => 12; @override - int get hashCode => Object.hash(Firo, network); + int get fractionDigits => 8; + + @override + bool get hasBuySupport => false; + + @override + bool get hasMnemonicPassphraseSupport => true; + + @override + List<int> get possibleMnemonicLengths => [defaultSeedPhraseLength, 24]; + + @override + AddressType get primaryAddressType => AddressType.p2pkh; + + @override + BigInt get satsPerCoin => BigInt.from(100000000); + + @override + int get targetBlockTimeSeconds => 150; + + @override + DerivePathType get primaryDerivePathType => DerivePathType.bip44; + + @override + Uri defaultBlockExplorer(String txid) { + switch (network) { + case CryptoCurrencyNetwork.main: + return Uri.parse("https://explorer.firo.org/tx/$txid"); + case CryptoCurrencyNetwork.test: + return Uri.parse("https://testexplorer.firo.org/tx/$txid"); + default: + throw Exception( + "Unsupported network for defaultBlockExplorer(): $network", + ); + } + } } diff --git a/lib/wallets/crypto_currency/coins/litecoin.dart b/lib/wallets/crypto_currency/coins/litecoin.dart index efccbb3de..e4b491cef 100644 --- a/lib/wallets/crypto_currency/coins/litecoin.dart +++ b/lib/wallets/crypto_currency/coins/litecoin.dart @@ -3,23 +3,49 @@ import 'package:stackwallet/models/isar/models/blockchain_data/address.dart'; import 'package:stackwallet/models/node_model.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/default_nodes.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; +import 'package:stackwallet/wallets/crypto_currency/interfaces/electrumx_currency_interface.dart'; import 'package:stackwallet/wallets/crypto_currency/intermediate/bip39_hd_currency.dart'; -class Litecoin extends Bip39HDCurrency { +class Litecoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { Litecoin(super.network) { + _idMain = "litecoin"; + _uriScheme = "litecoin"; switch (network) { case CryptoCurrencyNetwork.main: - coin = Coin.litecoin; + _id = _idMain; + _name = "Litecoin"; + _ticker = "LTC"; case CryptoCurrencyNetwork.test: - coin = Coin.litecoinTestNet; + _id = "litecoinTestNet"; + _name = "tLitecoin"; + _ticker = "tLTC"; default: throw Exception("Unsupported network: $network"); } } + late final String _id; + @override + String get identifier => _id; + + late final String _idMain; + @override + String get mainNetId => _idMain; + + late final String _name; + @override + String get prettyName => _name; + + late final String _uriScheme; + @override + String get uriScheme => _uriScheme; + + late final String _ticker; + @override + String get ticker => _ticker; + @override // change this to change the number of confirms a tx needs in order to show as confirmed int get minConfirms => 1; @@ -187,10 +213,10 @@ class Litecoin extends Bip39HDCurrency { host: "litecoin.stackwallet.com", port: 20063, name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.litecoin), + id: DefaultNodes.buildId(this), useSSL: true, enabled: true, - coinName: Coin.litecoin.name, + coinName: identifier, isFailover: true, isDown: false, ); @@ -200,10 +226,10 @@ class Litecoin extends Bip39HDCurrency { host: "litecoin.stackwallet.com", port: 51002, name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.litecoinTestNet), + id: DefaultNodes.buildId(this), useSSL: true, enabled: true, - coinName: Coin.litecoinTestNet.name, + coinName: identifier, isFailover: true, isDown: false, ); @@ -214,10 +240,43 @@ class Litecoin extends Bip39HDCurrency { } @override - bool operator ==(Object other) { - return other is Litecoin && other.network == network; - } + int get defaultSeedPhraseLength => 12; @override - int get hashCode => Object.hash(Litecoin, network); + int get fractionDigits => 8; + + @override + bool get hasBuySupport => true; + + @override + bool get hasMnemonicPassphraseSupport => true; + + @override + List<int> get possibleMnemonicLengths => [defaultSeedPhraseLength, 24]; + + @override + AddressType get primaryAddressType => AddressType.p2wpkh; + + @override + BigInt get satsPerCoin => BigInt.from(100000000); + + @override + int get targetBlockTimeSeconds => 150; + + @override + DerivePathType get primaryDerivePathType => DerivePathType.bip84; + + @override + Uri defaultBlockExplorer(String txid) { + switch (network) { + case CryptoCurrencyNetwork.main: + return Uri.parse("https://chain.so/tx/LTC/$txid"); + case CryptoCurrencyNetwork.test: + return Uri.parse("https://chain.so/tx/LTCTEST/$txid"); + default: + throw Exception( + "Unsupported network for defaultBlockExplorer(): $network", + ); + } + } } diff --git a/lib/wallets/crypto_currency/coins/monero.dart b/lib/wallets/crypto_currency/coins/monero.dart index 34eff8203..42afdf8df 100644 --- a/lib/wallets/crypto_currency/coins/monero.dart +++ b/lib/wallets/crypto_currency/coins/monero.dart @@ -1,20 +1,44 @@ import 'package:cw_monero/api/wallet.dart' as monero_wallet; import 'package:stackwallet/models/node_model.dart'; import 'package:stackwallet/utilities/default_nodes.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/crypto_currency/intermediate/cryptonote_currency.dart'; class Monero extends CryptonoteCurrency { Monero(super.network) { + _idMain = "monero"; + _uriScheme = "monero"; switch (network) { case CryptoCurrencyNetwork.main: - coin = Coin.monero; + _id = _idMain; + _name = "Monero"; + _ticker = "XMR"; default: throw Exception("Unsupported network: $network"); } } + late final String _id; + @override + String get identifier => _id; + + late final String _idMain; + @override + String get mainNetId => _idMain; + + late final String _name; + @override + String get prettyName => _name; + + late final String _uriScheme; + @override + String get uriScheme => _uriScheme; + + late final String _ticker; + @override + String get ticker => _ticker; + @override int get minConfirms => 10; @@ -31,10 +55,10 @@ class Monero extends CryptonoteCurrency { host: "https://monero.stackwallet.com", port: 18081, name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.monero), + id: DefaultNodes.buildId(this), useSSL: true, enabled: true, - coinName: Coin.monero.name, + coinName: identifier, isFailover: true, isDown: false, trusted: true, @@ -46,10 +70,40 @@ class Monero extends CryptonoteCurrency { } @override - bool operator ==(Object other) { - return other is Monero && other.network == network; - } + int get defaultSeedPhraseLength => 25; @override - int get hashCode => Object.hash(Monero, network); + int get fractionDigits => 12; + + @override + bool get hasBuySupport => false; + + @override + bool get hasMnemonicPassphraseSupport => false; + + @override + List<int> get possibleMnemonicLengths => [defaultSeedPhraseLength]; + + @override + BigInt get satsPerCoin => BigInt.from(1000000000000); + + @override + int get targetBlockTimeSeconds => 120; + + @override + DerivePathType get primaryDerivePathType => throw UnsupportedError( + "$runtimeType does not use bitcoin style derivation paths", + ); + + @override + Uri defaultBlockExplorer(String txid) { + switch (network) { + case CryptoCurrencyNetwork.main: + return Uri.parse("https://xmrchain.net/tx/$txid"); + default: + throw Exception( + "Unsupported network for defaultBlockExplorer(): $network", + ); + } + } } diff --git a/lib/wallets/crypto_currency/coins/namecoin.dart b/lib/wallets/crypto_currency/coins/namecoin.dart index c2cff8e57..53c0be5f9 100644 --- a/lib/wallets/crypto_currency/coins/namecoin.dart +++ b/lib/wallets/crypto_currency/coins/namecoin.dart @@ -3,21 +3,45 @@ import 'package:stackwallet/models/isar/models/blockchain_data/address.dart'; import 'package:stackwallet/models/node_model.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/default_nodes.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; +import 'package:stackwallet/wallets/crypto_currency/interfaces/electrumx_currency_interface.dart'; import 'package:stackwallet/wallets/crypto_currency/intermediate/bip39_hd_currency.dart'; -class Namecoin extends Bip39HDCurrency { +class Namecoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { Namecoin(super.network) { + _idMain = "namecoin"; + _uriScheme = "namecoin"; switch (network) { case CryptoCurrencyNetwork.main: - coin = Coin.namecoin; + _id = _idMain; + _name = "Namecoin"; + _ticker = "NMC"; default: throw Exception("Unsupported network: $network"); } } + late final String _id; + @override + String get identifier => _id; + + late final String _idMain; + @override + String get mainNetId => _idMain; + + late final String _name; + @override + String get prettyName => _name; + + late final String _uriScheme; + @override + String get uriScheme => _uriScheme; + + late final String _ticker; + @override + String get ticker => _ticker; + @override // See https://github.com/cypherstack/stack_wallet/blob/621aff47969761014e0a6c4e699cb637d5687ab3/lib/services/coins/namecoin/namecoin_wallet.dart#L58 int get minConfirms => 2; @@ -71,10 +95,10 @@ class Namecoin extends Bip39HDCurrency { host: "namecoin.stackwallet.com", port: 57002, name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.namecoin), + id: DefaultNodes.buildId(this), useSSL: true, enabled: true, - coinName: Coin.namecoin.name, + coinName: identifier, isFailover: true, isDown: false, ); @@ -87,8 +111,10 @@ class Namecoin extends Bip39HDCurrency { @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: Coin.particl.decimals); + 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 @@ -187,10 +213,41 @@ class Namecoin extends Bip39HDCurrency { } @override - bool operator ==(Object other) { - return other is Namecoin && other.network == network; - } + int get defaultSeedPhraseLength => 12; @override - int get hashCode => Object.hash(Namecoin, network); + int get fractionDigits => 8; + + @override + bool get hasBuySupport => false; + + @override + bool get hasMnemonicPassphraseSupport => true; + + @override + List<int> get possibleMnemonicLengths => [defaultSeedPhraseLength, 12]; + + @override + AddressType get primaryAddressType => AddressType.p2wpkh; + + @override + BigInt get satsPerCoin => BigInt.from(100000000); + + @override + int get targetBlockTimeSeconds => 600; + + @override + DerivePathType get primaryDerivePathType => DerivePathType.bip84; + + @override + Uri defaultBlockExplorer(String txid) { + switch (network) { + case CryptoCurrencyNetwork.main: + return Uri.parse("https://chainz.cryptoid.info/nmc/tx.dws?$txid.htm"); + default: + throw Exception( + "Unsupported network for defaultBlockExplorer(): $network", + ); + } + } } diff --git a/lib/wallets/crypto_currency/coins/nano.dart b/lib/wallets/crypto_currency/coins/nano.dart index 277a4601f..03632e352 100644 --- a/lib/wallets/crypto_currency/coins/nano.dart +++ b/lib/wallets/crypto_currency/coins/nano.dart @@ -1,7 +1,8 @@ import 'package:nanodart/nanodart.dart'; +import 'package:stackwallet/models/isar/models/isar_models.dart'; import 'package:stackwallet/models/node_model.dart'; import 'package:stackwallet/utilities/default_nodes.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/crypto_currency/intermediate/nano_currency.dart'; @@ -9,15 +10,50 @@ class Nano extends NanoCurrency { Nano(super.network) { switch (network) { case CryptoCurrencyNetwork.main: - coin = Coin.nano; + _id = "nano"; + _idMain = "nano"; + _name = "Nano"; + _uriScheme = "nano"; + _ticker = "XNO"; default: throw Exception("Unsupported network: $network"); } } + late final String _id; + @override + String get identifier => _id; + + late final String _idMain; + @override + String get mainNetId => _idMain; + + late final String _name; + @override + String get prettyName => _name; + + late final String _uriScheme; + @override + String get uriScheme => _uriScheme; + + late final String _ticker; + @override + String get ticker => _ticker; + + @override + int get fractionDigits => 30; + + @override + BigInt get satsPerCoin => BigInt.parse( + "1000000000000000000000000000000", + ); // 1*10^30 + @override int get minConfirms => 1; + @override + AddressType get primaryAddressType => AddressType.nano; + @override String get defaultRepresentative => "nano_38713x95zyjsqzx6nm1dsom1jmm668owkeb9913ax6nfgj15az3nu8xkx579"; @@ -33,10 +69,10 @@ class Nano extends NanoCurrency { host: "https://rainstorm.city/api", port: 443, name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.nano), + id: DefaultNodes.buildId(this), useSSL: true, enabled: true, - coinName: Coin.nano.name, + coinName: identifier, isFailover: true, isDown: false, ); @@ -47,10 +83,19 @@ class Nano extends NanoCurrency { } @override - bool operator ==(Object other) { - return other is Nano && other.network == network; - } + DerivePathType get primaryDerivePathType => throw UnsupportedError( + "$runtimeType does not use bitcoin style derivation paths", + ); @override - int get hashCode => Object.hash(Nano, network); + Uri defaultBlockExplorer(String txid) { + switch (network) { + case CryptoCurrencyNetwork.main: + return Uri.parse("https://www.nanolooker.com/block/$txid"); + default: + throw Exception( + "Unsupported network for defaultBlockExplorer(): $network", + ); + } + } } diff --git a/lib/wallets/crypto_currency/coins/particl.dart b/lib/wallets/crypto_currency/coins/particl.dart index ae73d46e5..7db0053f7 100644 --- a/lib/wallets/crypto_currency/coins/particl.dart +++ b/lib/wallets/crypto_currency/coins/particl.dart @@ -3,21 +3,45 @@ import 'package:stackwallet/models/isar/models/blockchain_data/address.dart'; import 'package:stackwallet/models/node_model.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/default_nodes.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; +import 'package:stackwallet/wallets/crypto_currency/interfaces/electrumx_currency_interface.dart'; import 'package:stackwallet/wallets/crypto_currency/intermediate/bip39_hd_currency.dart'; -class Particl extends Bip39HDCurrency { +class Particl extends Bip39HDCurrency with ElectrumXCurrencyInterface { Particl(super.network) { + _idMain = "particl"; + _uriScheme = "particl"; switch (network) { case CryptoCurrencyNetwork.main: - coin = Coin.particl; + _id = _idMain; + _name = "Particl"; + _ticker = "PART"; default: throw Exception("Unsupported network: $network"); } } + late final String _id; + @override + String get identifier => _id; + + late final String _idMain; + @override + String get mainNetId => _idMain; + + late final String _name; + @override + String get prettyName => _name; + + late final String _uriScheme; + @override + String get uriScheme => _uriScheme; + + late final String _ticker; + @override + String get ticker => _ticker; + @override // See https://github.com/cypherstack/stack_wallet/blob/d08b5c9b22b58db800ad07b2ceeb44c6d05f9cf3/lib/services/coins/particl/particl_wallet.dart#L57 int get minConfirms => 1; @@ -65,10 +89,10 @@ class Particl extends Bip39HDCurrency { host: "particl.stackwallet.com", port: 58002, name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.particl), + id: DefaultNodes.buildId(this), useSSL: true, enabled: true, - coinName: Coin.particl.name, + coinName: identifier, isFailover: true, isDown: false, ); @@ -83,7 +107,7 @@ class Particl extends Bip39HDCurrency { // 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: Coin.particl.decimals, + fractionDigits: fractionDigits, ); @override @@ -167,10 +191,41 @@ class Particl extends Bip39HDCurrency { } @override - bool operator ==(Object other) { - return other is Particl && other.network == network; - } + int get defaultSeedPhraseLength => 12; @override - int get hashCode => Object.hash(Particl, network); + int get fractionDigits => 8; + + @override + bool get hasBuySupport => false; + + @override + bool get hasMnemonicPassphraseSupport => true; + + @override + List<int> get possibleMnemonicLengths => [defaultSeedPhraseLength, 24]; + + @override + AddressType get primaryAddressType => AddressType.p2wpkh; + + @override + BigInt get satsPerCoin => BigInt.from(100000000); + + @override + int get targetBlockTimeSeconds => 600; + + @override + DerivePathType get primaryDerivePathType => DerivePathType.bip84; + + @override + Uri defaultBlockExplorer(String txid) { + switch (network) { + case CryptoCurrencyNetwork.main: + return Uri.parse("https://chainz.cryptoid.info/part/tx.dws?$txid.htm"); + default: + throw Exception( + "Unsupported network for defaultBlockExplorer(): $network", + ); + } + } } diff --git a/lib/wallets/crypto_currency/coins/peercoin.dart b/lib/wallets/crypto_currency/coins/peercoin.dart index 4e54329de..c14aa5303 100644 --- a/lib/wallets/crypto_currency/coins/peercoin.dart +++ b/lib/wallets/crypto_currency/coins/peercoin.dart @@ -4,23 +4,49 @@ import 'package:stackwallet/models/isar/models/blockchain_data/address.dart'; import 'package:stackwallet/models/node_model.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/default_nodes.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; +import 'package:stackwallet/wallets/crypto_currency/interfaces/electrumx_currency_interface.dart'; import 'package:stackwallet/wallets/crypto_currency/intermediate/bip39_hd_currency.dart'; -class Peercoin extends Bip39HDCurrency { +class Peercoin extends Bip39HDCurrency with ElectrumXCurrencyInterface { Peercoin(super.network) { + _idMain = "peercoin"; + _uriScheme = "peercoin"; switch (network) { case CryptoCurrencyNetwork.main: - coin = Coin.peercoin; + _id = "peercoin"; + _name = "Peercoin"; + _ticker = "PPC"; case CryptoCurrencyNetwork.test: - coin = Coin.peercoinTestNet; + _id = "peercoinTestNet"; + _name = "tPeercoin"; + _ticker = "tPPC"; default: throw Exception("Unsupported network: $network"); } } + late final String _id; + @override + String get identifier => _id; + + late final String _idMain; + @override + String get mainNetId => _idMain; + + late final String _name; + @override + String get prettyName => _name; + + late final String _uriScheme; + @override + String get uriScheme => _uriScheme; + + late final String _ticker; + @override + String get ticker => _ticker; + @override int get minConfirms => 1; @@ -66,9 +92,31 @@ class Peercoin extends Bip39HDCurrency { NodeModel get defaultNode { switch (network) { case CryptoCurrencyNetwork.main: - return DefaultNodes.peercoin; + return NodeModel( + host: "electrum.peercoinexplorer.net", + port: 50002, + name: DefaultNodes.defaultName, + id: DefaultNodes.buildId(this), + useSSL: true, + enabled: true, + coinName: identifier, + isFailover: true, + isDown: false, + ); + case CryptoCurrencyNetwork.test: - return DefaultNodes.peercoinTestNet; + return NodeModel( + host: "testnet-electrum.peercoinexplorer.net", + port: 50002, + name: DefaultNodes.defaultName, + id: DefaultNodes.buildId(this), + useSSL: true, + enabled: true, + coinName: identifier, + isFailover: true, + isDown: false, + ); + default: throw UnimplementedError(); } @@ -76,8 +124,9 @@ class Peercoin extends Bip39HDCurrency { @override Amount get dustLimit => Amount( + // TODO should this be 10000 instead of 294 for peercoin? rawValue: BigInt.from(294), - fractionDigits: Coin.peercoin.decimals, + fractionDigits: fractionDigits, ); @override @@ -162,10 +211,45 @@ class Peercoin extends Bip39HDCurrency { } @override - bool operator ==(Object other) { - return other is Peercoin && other.network == network; - } + int get defaultSeedPhraseLength => 12; @override - int get hashCode => Object.hash(Peercoin, network); + int get fractionDigits => 6; + + @override + bool get hasBuySupport => false; + + @override + bool get hasMnemonicPassphraseSupport => true; + + @override + List<int> get possibleMnemonicLengths => [defaultSeedPhraseLength, 24]; + + @override + AddressType get primaryAddressType => AddressType.p2wpkh; + + @override + BigInt get satsPerCoin => BigInt.from(1000000); // 1*10^6. + + @override + int get targetBlockTimeSeconds => 600; + + @override + DerivePathType get primaryDerivePathType => DerivePathType.bip84; + + @override + Uri defaultBlockExplorer(String txid) { + switch (network) { + case CryptoCurrencyNetwork.main: + return Uri.parse("https://chainz.cryptoid.info/ppc/tx.dws?$txid.htm"); + case CryptoCurrencyNetwork.test: + return Uri.parse( + "https://chainz.cryptoid.info/ppc-test/search.dws?q=$txid.htm", + ); + default: + throw Exception( + "Unsupported network for defaultBlockExplorer(): $network", + ); + } + } } diff --git a/lib/wallets/crypto_currency/coins/solana.dart b/lib/wallets/crypto_currency/coins/solana.dart index 6b01b5b6d..3916c5320 100644 --- a/lib/wallets/crypto_currency/coins/solana.dart +++ b/lib/wallets/crypto_currency/coins/solana.dart @@ -1,20 +1,45 @@ import 'package:solana/solana.dart'; +import 'package:stackwallet/models/isar/models/blockchain_data/address.dart'; import 'package:stackwallet/models/node_model.dart'; import 'package:stackwallet/utilities/default_nodes.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/crypto_currency/intermediate/bip39_currency.dart'; class Solana extends Bip39Currency { Solana(super.network) { + _idMain = "solana"; + _uriScheme = "solana"; switch (network) { case CryptoCurrencyNetwork.main: - coin = Coin.solana; + _id = _idMain; + _name = "Solana"; + _ticker = "SOL"; default: throw Exception("Unsupported network: $network"); } } + late final String _id; + @override + String get identifier => _id; + + late final String _idMain; + @override + String get mainNetId => _idMain; + + late final String _name; + @override + String get prettyName => _name; + + late final String _uriScheme; + @override + String get uriScheme => _uriScheme; + + late final String _ticker; + @override + String get ticker => _ticker; + @override NodeModel get defaultNode { switch (network) { @@ -24,10 +49,10 @@ class Solana extends Bip39Currency { "https://api.mainnet-beta.solana.com/", // TODO: Change this to stack wallet one port: 443, name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.solana), + id: DefaultNodes.buildId(this), useSSL: true, enabled: true, - coinName: Coin.solana.name, + coinName: identifier, isFailover: true, isDown: false, ); @@ -52,10 +77,41 @@ class Solana extends Bip39Currency { String get genesisHash => throw UnimplementedError(); @override - bool operator ==(Object other) { - return other is Solana && other.network == network; - } + int get defaultSeedPhraseLength => 12; @override - int get hashCode => Object.hash(Solana, network); + int get fractionDigits => 9; + + @override + bool get hasBuySupport => false; + + @override + bool get hasMnemonicPassphraseSupport => false; + + @override + List<int> get possibleMnemonicLengths => [defaultSeedPhraseLength, 24]; + + @override + AddressType get primaryAddressType => AddressType.solana; + + @override + BigInt get satsPerCoin => BigInt.from(1000000000); + + @override + int get targetBlockTimeSeconds => 1; + + @override + DerivePathType get primaryDerivePathType => DerivePathType.solana; + + @override + Uri defaultBlockExplorer(String txid) { + switch (network) { + case CryptoCurrencyNetwork.main: + return Uri.parse("https://explorer.solana.com/tx/$txid"); + default: + throw Exception( + "Unsupported network for defaultBlockExplorer(): $network", + ); + } + } } diff --git a/lib/wallets/crypto_currency/coins/stellar.dart b/lib/wallets/crypto_currency/coins/stellar.dart index e9a7e605b..28165179a 100644 --- a/lib/wallets/crypto_currency/coins/stellar.dart +++ b/lib/wallets/crypto_currency/coins/stellar.dart @@ -1,21 +1,48 @@ +import 'package:stackwallet/models/isar/models/blockchain_data/address.dart'; import 'package:stackwallet/models/node_model.dart'; import 'package:stackwallet/utilities/default_nodes.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/crypto_currency/intermediate/bip39_currency.dart'; class Stellar extends Bip39Currency { Stellar(super.network) { + _idMain = "stellar"; + _uriScheme = "stellar"; switch (network) { case CryptoCurrencyNetwork.main: - coin = Coin.stellar; + _id = _idMain; + _name = "Stellar"; + _ticker = "XLM"; case CryptoCurrencyNetwork.test: - coin = Coin.stellarTestnet; + _id = "stellarTestnet"; + _name = "tStellar"; + _ticker = "tXLM"; default: throw Exception("Unsupported network: $network"); } } + late final String _id; + @override + String get identifier => _id; + + late final String _idMain; + @override + String get mainNetId => _idMain; + + late final String _name; + @override + String get prettyName => _name; + + late final String _uriScheme; + @override + String get uriScheme => _uriScheme; + + late final String _ticker; + @override + String get ticker => _ticker; + @override int get minConfirms => 1; @@ -31,9 +58,31 @@ class Stellar extends Bip39Currency { NodeModel get defaultNode { switch (network) { case CryptoCurrencyNetwork.main: - return DefaultNodes.stellar; + return NodeModel( + host: "https://horizon.stellar.org", + port: 443, + name: DefaultNodes.defaultName, + id: DefaultNodes.buildId(this), + useSSL: false, + enabled: true, + coinName: identifier, + isFailover: true, + isDown: false, + ); + case CryptoCurrencyNetwork.test: - return DefaultNodes.stellarTestnet; + return NodeModel( + host: "https://horizon-testnet.stellar.org/", + port: 50022, + name: DefaultNodes.defaultName, + id: DefaultNodes.buildId(this), + useSSL: true, + enabled: true, + coinName: identifier, + isFailover: true, + isDown: false, + ); + default: throw Exception("Unsupported network"); } @@ -44,10 +93,46 @@ class Stellar extends Bip39Currency { RegExp(r"^[G][A-Z0-9]{55}$").hasMatch(address); @override - bool operator ==(Object other) { - return other is Stellar && other.network == network; - } + int get defaultSeedPhraseLength => 24; @override - int get hashCode => Object.hash(Stellar, network); + int get fractionDigits => 7; + + @override + bool get hasBuySupport => false; + + @override + bool get hasMnemonicPassphraseSupport => true; + + @override + List<int> get possibleMnemonicLengths => [defaultSeedPhraseLength, 12]; + + @override + AddressType get primaryAddressType => AddressType.stellar; + + @override + 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 primaryDerivePathType => throw UnsupportedError( + "$runtimeType does not use bitcoin style derivation paths",); + + @override + Uri defaultBlockExplorer(String txid) { + switch (network) { + case CryptoCurrencyNetwork.main: + return Uri.parse("https://stellarchain.io/tx/$txid"); + case CryptoCurrencyNetwork.test: + return Uri.parse("https://testnet.stellarchain.io/transactions/$txid"); + default: + throw Exception( + "Unsupported network for defaultBlockExplorer(): $network", + ); + } + } } diff --git a/lib/wallets/crypto_currency/coins/tezos.dart b/lib/wallets/crypto_currency/coins/tezos.dart index efb982867..e8eb63a97 100644 --- a/lib/wallets/crypto_currency/coins/tezos.dart +++ b/lib/wallets/crypto_currency/coins/tezos.dart @@ -6,7 +6,7 @@ import 'package:coinlib_flutter/coinlib_flutter.dart'; import 'package:stackwallet/models/isar/models/blockchain_data/address.dart'; import 'package:stackwallet/models/node_model.dart'; import 'package:stackwallet/utilities/default_nodes.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/crypto_currency/intermediate/bip39_currency.dart'; import 'package:tezart/src/crypto/crypto.dart'; @@ -14,14 +14,38 @@ import 'package:tezart/tezart.dart'; class Tezos extends Bip39Currency { Tezos(super.network) { + _idMain = "tezos"; + _uriScheme = "tezos"; switch (network) { case CryptoCurrencyNetwork.main: - coin = Coin.tezos; + _id = _idMain; + _name = "Tezos"; + _ticker = "XTZ"; default: throw Exception("Unsupported network: $network"); } } + late final String _id; + @override + String get identifier => _id; + + late final String _idMain; + @override + String get mainNetId => _idMain; + + late final String _name; + @override + String get prettyName => _name; + + late final String _uriScheme; + @override + String get uriScheme => _uriScheme; + + late final String _ticker; + @override + String get ticker => _ticker; + // =========================================================================== // =========== Public ======================================================== @@ -83,13 +107,14 @@ class Tezos extends Bip39Currency { switch (network) { case CryptoCurrencyNetwork.main: return NodeModel( + // TODO: ?Change this to stack wallet one? host: "https://mainnet.api.tez.ie", port: 443, name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.tezos), + id: DefaultNodes.buildId(this), useSSL: true, enabled: true, - coinName: Coin.tezos.name, + coinName: identifier, isFailover: true, isDown: false, ); @@ -148,13 +173,43 @@ class Tezos extends Bip39Currency { }).toList(); } - // =========================================================================== + @override + int get defaultSeedPhraseLength => 24; @override - bool operator ==(Object other) { - return other is Tezos && other.network == network; + int get fractionDigits => 6; + + @override + bool get hasBuySupport => false; + + @override + bool get hasMnemonicPassphraseSupport => false; + + @override + List<int> get possibleMnemonicLengths => [defaultSeedPhraseLength, 12]; + + @override + AddressType get primaryAddressType => AddressType.tezos; + + @override + BigInt get satsPerCoin => BigInt.from(1000000); + + @override + int get targetBlockTimeSeconds => 60; + + @override + DerivePathType get primaryDerivePathType => + throw UnsupportedError("Is this even used?"); + + @override + Uri defaultBlockExplorer(String txid) { + switch (network) { + case CryptoCurrencyNetwork.main: + return Uri.parse("https://tzstats.com/$txid"); + default: + throw Exception( + "Unsupported network for defaultBlockExplorer(): $network", + ); + } } - - @override - int get hashCode => Object.hash(Tezos, network); } diff --git a/lib/wallets/crypto_currency/coins/wownero.dart b/lib/wallets/crypto_currency/coins/wownero.dart index 549d1739f..788c810e0 100644 --- a/lib/wallets/crypto_currency/coins/wownero.dart +++ b/lib/wallets/crypto_currency/coins/wownero.dart @@ -1,20 +1,44 @@ import 'package:cw_wownero/api/wallet.dart' as wownero_wallet; import 'package:stackwallet/models/node_model.dart'; import 'package:stackwallet/utilities/default_nodes.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/crypto_currency/intermediate/cryptonote_currency.dart'; class Wownero extends CryptonoteCurrency { Wownero(super.network) { + _idMain = "wownero"; + _uriScheme = "wownero"; switch (network) { case CryptoCurrencyNetwork.main: - coin = Coin.wownero; + _id = _idMain; + _name = "Wownero"; + _ticker = "WOW"; default: throw Exception("Unsupported network: $network"); } } + late final String _id; + @override + String get identifier => _id; + + late final String _idMain; + @override + String get mainNetId => _idMain; + + late final String _name; + @override + String get prettyName => _name; + + late final String _uriScheme; + @override + String get uriScheme => _uriScheme; + + late final String _ticker; + @override + String get ticker => _ticker; + @override int get minConfirms => 15; @@ -31,10 +55,10 @@ class Wownero extends CryptonoteCurrency { host: "https://wownero.stackwallet.com", port: 34568, name: DefaultNodes.defaultName, - id: DefaultNodes.buildId(Coin.wownero), + id: DefaultNodes.buildId(this), useSSL: true, enabled: true, - coinName: Coin.wownero.name, + coinName: identifier, isFailover: true, isDown: false, trusted: true, @@ -46,10 +70,40 @@ class Wownero extends CryptonoteCurrency { } @override - bool operator ==(Object other) { - return other is Wownero && other.network == network; - } + int get defaultSeedPhraseLength => 14; @override - int get hashCode => Object.hash(Wownero, network); + int get fractionDigits => 11; + + @override + bool get hasBuySupport => false; + + @override + bool get hasMnemonicPassphraseSupport => false; + + @override + List<int> get possibleMnemonicLengths => [defaultSeedPhraseLength, 25]; + + @override + BigInt get satsPerCoin => BigInt.from(100000000000); + + @override + int get targetBlockTimeSeconds => 120; + + @override + DerivePathType get primaryDerivePathType => throw UnsupportedError( + "$runtimeType does not use bitcoin style derivation paths", + ); + + @override + Uri defaultBlockExplorer(String txid) { + switch (network) { + case CryptoCurrencyNetwork.main: + return Uri.parse("https://explore.wownero.com/search?value=$txid"); + default: + throw Exception( + "Unsupported network for defaultBlockExplorer(): $network", + ); + } + } } diff --git a/lib/wallets/crypto_currency/crypto_currency.dart b/lib/wallets/crypto_currency/crypto_currency.dart index 8b6f5cdb6..5a8e3e723 100644 --- a/lib/wallets/crypto_currency/crypto_currency.dart +++ b/lib/wallets/crypto_currency/crypto_currency.dart @@ -1,6 +1,6 @@ +import 'package:stackwallet/models/isar/models/blockchain_data/address.dart'; import 'package:stackwallet/models/node_model.dart'; -import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart'; enum CryptoCurrencyNetwork { main, @@ -9,13 +9,26 @@ enum CryptoCurrencyNetwork { } abstract class CryptoCurrency { - @Deprecated("[prio=low] Should eventually move away from Coin enum") - late final Coin coin; + // @Deprecated("[prio=low] Should eventually move away from Coin enum") + // late final CryptoCurrency coin; final CryptoCurrencyNetwork network; CryptoCurrency(this.network); + // Identifier should be unique. + /// This [identifier] should also match the old `Coin` enum name for each + /// respective coin as it is used to differentiate between coins in persistent + /// storage. + String get identifier; + + /// Should be the [identifier] of the main net version of the currency + String get mainNetId; + + String get ticker; + String get prettyName; + String get uriScheme; + // override in subclass if the currency has tokens on it's network // (used for eth currently) bool get hasTokenSupport => false; @@ -23,10 +36,6 @@ abstract class CryptoCurrency { // Override in subclass if the currency has Tor support: bool get torSupport => false; - // TODO: [prio=low] require these be overridden in concrete implementations to remove reliance on [coin] - int get fractionDigits => coin.decimals; - BigInt get satsPerCoin => Constants.satsPerCoin(coin); - int get minConfirms; // TODO: [prio=low] could be handled differently as (at least) epiccash does not use this @@ -35,4 +44,26 @@ abstract class CryptoCurrency { bool validateAddress(String address); NodeModel get defaultNode; + + int get defaultSeedPhraseLength; + int get fractionDigits; + bool get hasBuySupport; + bool get hasMnemonicPassphraseSupport; + List<int> get possibleMnemonicLengths; + AddressType get primaryAddressType; + BigInt get satsPerCoin; + int get targetBlockTimeSeconds; + DerivePathType get primaryDerivePathType; + + Uri defaultBlockExplorer(String txid); + + @override + bool operator ==(Object other) { + return other is CryptoCurrency && + other.runtimeType == runtimeType && + other.network == network; + } + + @override + int get hashCode => Object.hash(runtimeType, network); } diff --git a/lib/wallets/crypto_currency/interfaces/electrumx_currency_interface.dart b/lib/wallets/crypto_currency/interfaces/electrumx_currency_interface.dart new file mode 100644 index 000000000..69c9f33fd --- /dev/null +++ b/lib/wallets/crypto_currency/interfaces/electrumx_currency_interface.dart @@ -0,0 +1,5 @@ +import 'package:stackwallet/wallets/crypto_currency/intermediate/bip39_hd_currency.dart'; + +mixin ElectrumXCurrencyInterface on Bip39HDCurrency { + // +} diff --git a/lib/wallets/crypto_currency/interfaces/paynym_currency_interface.dart b/lib/wallets/crypto_currency/interfaces/paynym_currency_interface.dart index 6f5571009..580a1b3ed 100644 --- a/lib/wallets/crypto_currency/interfaces/paynym_currency_interface.dart +++ b/lib/wallets/crypto_currency/interfaces/paynym_currency_interface.dart @@ -1,7 +1,8 @@ import 'package:stackwallet/utilities/amount/amount.dart'; +import 'package:stackwallet/wallets/crypto_currency/interfaces/electrumx_currency_interface.dart'; import 'package:stackwallet/wallets/crypto_currency/intermediate/bip39_hd_currency.dart'; -mixin PaynymCurrencyInterface on Bip39HDCurrency { +mixin PaynymCurrencyInterface on ElectrumXCurrencyInterface, Bip39HDCurrency { Amount get dustLimitP2PKH => Amount( rawValue: BigInt.from(546), fractionDigits: fractionDigits, diff --git a/lib/wallets/crypto_currency/intermediate/cryptonote_currency.dart b/lib/wallets/crypto_currency/intermediate/cryptonote_currency.dart index 79d1f4de4..a513f84ae 100644 --- a/lib/wallets/crypto_currency/intermediate/cryptonote_currency.dart +++ b/lib/wallets/crypto_currency/intermediate/cryptonote_currency.dart @@ -1,3 +1,4 @@ +import 'package:stackwallet/models/isar/models/blockchain_data/address.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; abstract class CryptonoteCurrency extends CryptoCurrency { @@ -7,4 +8,7 @@ abstract class CryptonoteCurrency extends CryptoCurrency { String get genesisHash { return "not used in stack's cryptonote coins"; } + + @override + AddressType get primaryAddressType => AddressType.cryptonote; } diff --git a/lib/wallets/crypto_currency/intermediate/nano_currency.dart b/lib/wallets/crypto_currency/intermediate/nano_currency.dart index 617f8d952..72aba78bd 100644 --- a/lib/wallets/crypto_currency/intermediate/nano_currency.dart +++ b/lib/wallets/crypto_currency/intermediate/nano_currency.dart @@ -8,6 +8,21 @@ abstract class NanoCurrency extends Bip39Currency { int get nanoAccountType; + @override + bool get hasMnemonicPassphraseSupport => false; + + @override + int get targetBlockTimeSeconds => 1; // TODO: Verify this + + @override + bool get hasBuySupport => false; + + @override + int get defaultSeedPhraseLength => 24; + + @override + List<int> get possibleMnemonicLengths => [defaultSeedPhraseLength, 12]; + @override bool validateAddress(String address) => NanoAccounts.isValid( nanoAccountType, diff --git a/lib/wallets/isar/models/wallet_info.dart b/lib/wallets/isar/models/wallet_info.dart index 0ceaa6b83..0e07b6426 100644 --- a/lib/wallets/isar/models/wallet_info.dart +++ b/lib/wallets/isar/models/wallet_info.dart @@ -3,7 +3,8 @@ import 'dart:convert'; import 'package:isar/isar.dart'; import 'package:stackwallet/models/balance.dart'; import 'package:stackwallet/models/isar/models/blockchain_data/address.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/supported_coins.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/isar/isar_id_interface.dart'; import 'package:stackwallet/wallets/isar/models/wallet_info_meta.dart'; import 'package:uuid/uuid.dart'; @@ -76,9 +77,10 @@ class WalletInfo implements IsarId { @ignore Balance get cachedBalanceSecondary { if (cachedBalanceSecondaryString == null) { - return Balance.zeroForCoin(coin: coin); + return Balance.zeroFor(currency: coin); } else { - return Balance.fromJson(cachedBalanceSecondaryString!, coin.decimals); + return Balance.fromJson( + cachedBalanceSecondaryString!, coin.fractionDigits); } } @@ -86,21 +88,22 @@ class WalletInfo implements IsarId { @ignore Balance get cachedBalanceTertiary { if (cachedBalanceTertiaryString == null) { - return Balance.zeroForCoin(coin: coin); + return Balance.zeroFor(currency: coin); } else { - return Balance.fromJson(cachedBalanceTertiaryString!, coin.decimals); + return Balance.fromJson( + cachedBalanceTertiaryString!, coin.fractionDigits); } } @ignore - Coin get coin => Coin.values.byName(coinName); + CryptoCurrency get coin => SupportedCoins.getCryptoCurrencyFor(coinName); @ignore Balance get cachedBalance { if (cachedBalanceString == null) { - return Balance.zeroForCoin(coin: coin); + return Balance.zeroFor(currency: coin); } else { - return Balance.fromJson(cachedBalanceString!, coin.decimals); + return Balance.fromJson(cachedBalanceString!, coin.fractionDigits); } } @@ -404,7 +407,9 @@ class WalletInfo implements IsarId { this.cachedBalanceTertiaryString, this.otherDataJsonString, }) : assert( - Coin.values.map((e) => e.name).contains(coinName), + SupportedCoins.cryptocurrencies + .map((e) => e.identifier) + .contains(coinName), ); WalletInfo copyWith({ @@ -440,14 +445,14 @@ class WalletInfo implements IsarId { } static WalletInfo createNew({ - required Coin coin, + required CryptoCurrency coin, required String name, int restoreHeight = 0, String? walletIdOverride, String? otherDataJsonString, }) { return WalletInfo( - coinName: coin.name, + coinName: coin.identifier, walletId: walletIdOverride ?? const Uuid().v1(), name: name, mainAddressType: coin.primaryAddressType, @@ -461,9 +466,11 @@ class WalletInfo implements IsarId { Map<String, dynamic> jsonObject, AddressType mainAddressType, ) { - final coin = Coin.values.byName(jsonObject["coin"] as String); + final coin = SupportedCoins.getCryptoCurrencyFor( + jsonObject["coin"] as String, + ); return WalletInfo( - coinName: coin.name, + coinName: coin.identifier, walletId: jsonObject["id"] as String, name: jsonObject["name"] as String, mainAddressType: mainAddressType, @@ -475,7 +482,7 @@ class WalletInfo implements IsarId { return { "name": name, "id": walletId, - "coin": coin.name, + "coin": coin.identifier, }; } diff --git a/lib/wallets/isar/providers/all_wallets_info_provider.dart b/lib/wallets/isar/providers/all_wallets_info_provider.dart index bca6f417f..a51233a0c 100644 --- a/lib/wallets/isar/providers/all_wallets_info_provider.dart +++ b/lib/wallets/isar/providers/all_wallets_info_provider.dart @@ -4,7 +4,8 @@ import 'package:flutter/foundation.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:isar/isar.dart'; import 'package:stackwallet/providers/db/main_db_provider.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/supported_coins.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/isar/models/wallet_info.dart'; final pAllWalletsInfo = Provider((ref) { @@ -14,7 +15,8 @@ final pAllWalletsInfo = Provider((ref) { final pAllWalletsInfoByCoin = Provider((ref) { final infos = ref.watch(pAllWalletsInfo); - final Map<Coin, ({Coin coin, List<WalletInfo> wallets})> map = {}; + final Map<CryptoCurrency, ({CryptoCurrency coin, List<WalletInfo> wallets})> + map = {}; for (final info in infos) { if (map[info.coin] == null) { @@ -24,8 +26,8 @@ final pAllWalletsInfoByCoin = Provider((ref) { map[info.coin]!.wallets.add(info); } - final List<({Coin coin, List<WalletInfo> wallets})> results = []; - for (final coin in Coin.values) { + final List<({CryptoCurrency coin, List<WalletInfo> wallets})> results = []; + for (final coin in SupportedCoins.cryptocurrencies) { if (map[coin] != null) { results.add(map[coin]!); } diff --git a/lib/wallets/isar/providers/wallet_info_provider.dart b/lib/wallets/isar/providers/wallet_info_provider.dart index b2c39ec21..a8d4ba3f3 100644 --- a/lib/wallets/isar/providers/wallet_info_provider.dart +++ b/lib/wallets/isar/providers/wallet_info_provider.dart @@ -2,7 +2,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:isar/isar.dart'; import 'package:stackwallet/models/balance.dart'; import 'package:stackwallet/providers/db/main_db_provider.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/isar/models/wallet_info.dart'; import 'package:stackwallet/wallets/isar/providers/util/watcher.dart'; @@ -27,65 +27,81 @@ final pWalletInfo = Provider.family<WalletInfo, String>( }, ); -final pWalletCoin = Provider.family<Coin, String>( +final pWalletCoin = Provider.family<CryptoCurrency, String>( (ref, walletId) { - return ref.watch(_wiProvider(walletId) - .select((value) => (value.value as WalletInfo).coin)); + return ref.watch( + _wiProvider(walletId).select((value) => (value.value as WalletInfo).coin), + ); }, ); final pWalletBalance = Provider.family<Balance, String>( (ref, walletId) { - return ref.watch(_wiProvider(walletId) - .select((value) => (value.value as WalletInfo).cachedBalance)); + return ref.watch( + _wiProvider(walletId) + .select((value) => (value.value as WalletInfo).cachedBalance), + ); }, ); final pWalletBalanceSecondary = Provider.family<Balance, String>( (ref, walletId) { - return ref.watch(_wiProvider(walletId) - .select((value) => (value.value as WalletInfo).cachedBalanceSecondary)); + return ref.watch( + _wiProvider(walletId).select( + (value) => (value.value as WalletInfo).cachedBalanceSecondary), + ); }, ); final pWalletBalanceTertiary = Provider.family<Balance, String>( (ref, walletId) { - return ref.watch(_wiProvider(walletId) - .select((value) => (value.value as WalletInfo).cachedBalanceTertiary)); + return ref.watch( + _wiProvider(walletId) + .select((value) => (value.value as WalletInfo).cachedBalanceTertiary), + ); }, ); final pWalletChainHeight = Provider.family<int, String>( (ref, walletId) { - return ref.watch(_wiProvider(walletId) - .select((value) => (value.value as WalletInfo).cachedChainHeight)); + return ref.watch( + _wiProvider(walletId) + .select((value) => (value.value as WalletInfo).cachedChainHeight), + ); }, ); final pWalletIsFavourite = Provider.family<bool, String>( (ref, walletId) { - return ref.watch(_wiProvider(walletId) - .select((value) => (value.value as WalletInfo).isFavourite)); + return ref.watch( + _wiProvider(walletId) + .select((value) => (value.value as WalletInfo).isFavourite), + ); }, ); final pWalletName = Provider.family<String, String>( (ref, walletId) { - return ref.watch(_wiProvider(walletId) - .select((value) => (value.value as WalletInfo).name)); + return ref.watch( + _wiProvider(walletId).select((value) => (value.value as WalletInfo).name), + ); }, ); final pWalletReceivingAddress = Provider.family<String, String>( (ref, walletId) { - return ref.watch(_wiProvider(walletId) - .select((value) => (value.value as WalletInfo).cachedReceivingAddress)); + return ref.watch( + _wiProvider(walletId).select( + (value) => (value.value as WalletInfo).cachedReceivingAddress), + ); }, ); final pWalletTokenAddresses = Provider.family<List<String>, String>( (ref, walletId) { - return ref.watch(_wiProvider(walletId) - .select((value) => (value.value as WalletInfo).tokenContractAddresses)); + return ref.watch( + _wiProvider(walletId).select( + (value) => (value.value as WalletInfo).tokenContractAddresses), + ); }, ); diff --git a/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart b/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart index 5d0bb3ffc..ea10a3292 100644 --- a/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart +++ b/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart @@ -351,7 +351,7 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T> { final tx = await electrumXCachedClient.getTransaction( txHash: txHash["tx_hash"] as String, verbose: true, - coin: coin, + cryptoCurrency: coin, ); if (!_duplicateTxCheck(allTransactions, tx["txid"] as String)) { @@ -389,7 +389,7 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T> { final inputTx = await electrumXCachedClient.getTransaction( txHash: txid, - coin: cryptoCurrency.coin, + cryptoCurrency: cryptoCurrency, ); final prevOutJson = Map<String, dynamic>.from( @@ -724,7 +724,9 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T> { await _updateKnownSalts(updatedKnownSalts); } else { // clear cache - await electrumXCachedClient.clearSharedTransactionCache(coin: coin); + await electrumXCachedClient.clearSharedTransactionCache( + cryptoCurrency: coin, + ); await mainDB.deleteWalletBlockchainData(walletId); } @@ -1082,7 +1084,7 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T> { // TODO [prio=low]: Use ElectrumXInterface method. Future<void> _updateElectrumX() async { final failovers = nodeService - .failoverNodesFor(coin: cryptoCurrency.coin) + .failoverNodesFor(currency: cryptoCurrency) .map( (e) => ElectrumXNode( address: e.host, @@ -1137,7 +1139,7 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T> { final txn = await electrumXCachedClient.getTransaction( txHash: jsonUTXO["tx_hash"] as String, verbose: true, - coin: cryptoCurrency.coin, + cryptoCurrency: cryptoCurrency, ); final vout = jsonUTXO["tx_pos"] as int; diff --git a/lib/wallets/wallet/impl/bitcoincash_wallet.dart b/lib/wallets/wallet/impl/bitcoincash_wallet.dart index 2b9355e2d..af0d1e3d6 100644 --- a/lib/wallets/wallet/impl/bitcoincash_wallet.dart +++ b/lib/wallets/wallet/impl/bitcoincash_wallet.dart @@ -9,29 +9,30 @@ import 'package:stackwallet/services/coins/bitcoincash/bch_utils.dart'; import 'package:stackwallet/services/coins/bitcoincash/cashtokens.dart' as cash_tokens; import 'package:stackwallet/utilities/amount/amount.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart'; import 'package:stackwallet/utilities/extensions/extensions.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/wallets/crypto_currency/coins/bitcoincash.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; +import 'package:stackwallet/wallets/crypto_currency/interfaces/electrumx_currency_interface.dart'; import 'package:stackwallet/wallets/wallet/intermediate/bip39_hd_wallet.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/bcash_interface.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/cash_fusion_interface.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/coin_control_interface.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart'; -class BitcoincashWallet extends Bip39HDWallet +class BitcoincashWallet<T extends ElectrumXCurrencyInterface> + extends Bip39HDWallet<T> with - ElectrumXInterface, - BCashInterface, - CoinControlInterface, - CashFusionInterface { + ElectrumXInterface<T>, + BCashInterface<T>, + CoinControlInterface<T>, + CashFusionInterface<T> { @override int get isarTransactionVersion => 2; BitcoincashWallet(CryptoCurrencyNetwork network) - : super(Bitcoincash(network)); + : super(Bitcoincash(network) as T); @override FilterOperation? get changeAddressFilterOperation => FilterGroup.and( @@ -130,7 +131,7 @@ class BitcoincashWallet extends Bip39HDWallet final tx = await electrumXCachedClient.getTransaction( txHash: txHash["tx_hash"] as String, verbose: true, - coin: cryptoCurrency.coin, + cryptoCurrency: cryptoCurrency, ); // check for duplicates before adding to list @@ -171,7 +172,7 @@ class BitcoincashWallet extends Bip39HDWallet final inputTx = await electrumXCachedClient.getTransaction( txHash: txid, - coin: cryptoCurrency.coin, + cryptoCurrency: cryptoCurrency, ); try { @@ -361,7 +362,7 @@ class BitcoincashWallet extends Bip39HDWallet return Amount( rawValue: BigInt.from(((181 * inputCount) + (34 * outputCount) + 10) * (feeRatePerKB / 1000).ceil()), - fractionDigits: info.coin.decimals, + fractionDigits: info.coin.fractionDigits, ); } diff --git a/lib/wallets/wallet/impl/dogecoin_wallet.dart b/lib/wallets/wallet/impl/dogecoin_wallet.dart index 210ca64cd..a5f99fdbe 100644 --- a/lib/wallets/wallet/impl/dogecoin_wallet.dart +++ b/lib/wallets/wallet/impl/dogecoin_wallet.dart @@ -9,13 +9,14 @@ import 'package:stackwallet/utilities/extensions/extensions.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/wallets/crypto_currency/coins/dogecoin.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; +import 'package:stackwallet/wallets/crypto_currency/interfaces/electrumx_currency_interface.dart'; import 'package:stackwallet/wallets/wallet/intermediate/bip39_hd_wallet.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/coin_control_interface.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart'; -class DogecoinWallet extends Bip39HDWallet - with ElectrumXInterface, CoinControlInterface { - DogecoinWallet(CryptoCurrencyNetwork network) : super(Dogecoin(network)); +class DogecoinWallet<T extends ElectrumXCurrencyInterface> + extends Bip39HDWallet<T> with ElectrumXInterface<T>, CoinControlInterface { + DogecoinWallet(CryptoCurrencyNetwork network) : super(Dogecoin(network) as T); @override int get maximumFeerate => 2500000; // 1000x default value @@ -89,7 +90,7 @@ class DogecoinWallet extends Bip39HDWallet final tx = await electrumXCachedClient.getTransaction( txHash: txHash["tx_hash"] as String, verbose: true, - coin: cryptoCurrency.coin, + cryptoCurrency: cryptoCurrency, ); // Only tx to list once. @@ -131,7 +132,7 @@ class DogecoinWallet extends Bip39HDWallet final inputTx = await electrumXCachedClient.getTransaction( txHash: txid, - coin: cryptoCurrency.coin, + cryptoCurrency: cryptoCurrency, ); final prevOutJson = Map<String, dynamic>.from( diff --git a/lib/wallets/wallet/impl/ecash_wallet.dart b/lib/wallets/wallet/impl/ecash_wallet.dart index 2946c6069..e17525756 100644 --- a/lib/wallets/wallet/impl/ecash_wallet.dart +++ b/lib/wallets/wallet/impl/ecash_wallet.dart @@ -9,28 +9,28 @@ import 'package:stackwallet/services/coins/bitcoincash/bch_utils.dart'; import 'package:stackwallet/services/coins/bitcoincash/cashtokens.dart' as cash_tokens; import 'package:stackwallet/utilities/amount/amount.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart'; import 'package:stackwallet/utilities/extensions/extensions.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/wallets/crypto_currency/coins/ecash.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; +import 'package:stackwallet/wallets/crypto_currency/interfaces/electrumx_currency_interface.dart'; import 'package:stackwallet/wallets/wallet/intermediate/bip39_hd_wallet.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/bcash_interface.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/cash_fusion_interface.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/coin_control_interface.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart'; -class EcashWallet extends Bip39HDWallet +class EcashWallet<T extends ElectrumXCurrencyInterface> extends Bip39HDWallet<T> with - ElectrumXInterface, - BCashInterface, - CoinControlInterface, - CashFusionInterface { + ElectrumXInterface<T>, + BCashInterface<T>, + CoinControlInterface<T>, + CashFusionInterface<T> { @override int get isarTransactionVersion => 2; - EcashWallet(CryptoCurrencyNetwork network) : super(Ecash(network)); + EcashWallet(CryptoCurrencyNetwork network) : super(Ecash(network) as T); @override FilterOperation? get changeAddressFilterOperation => FilterGroup.and( @@ -123,7 +123,7 @@ class EcashWallet extends Bip39HDWallet final tx = await electrumXCachedClient.getTransaction( txHash: txHash["tx_hash"] as String, verbose: true, - coin: cryptoCurrency.coin, + cryptoCurrency: cryptoCurrency, ); // check for duplicates before adding to list @@ -164,7 +164,7 @@ class EcashWallet extends Bip39HDWallet final inputTx = await electrumXCachedClient.getTransaction( txHash: txid, - coin: cryptoCurrency.coin, + cryptoCurrency: cryptoCurrency, ); final prevOutJson = Map<String, dynamic>.from( @@ -353,7 +353,7 @@ class EcashWallet extends Bip39HDWallet return Amount( rawValue: BigInt.from(((181 * inputCount) + (34 * outputCount) + 10) * (feeRatePerKB / 1000).ceil()), - fractionDigits: info.coin.decimals, + fractionDigits: info.coin.fractionDigits, ); } diff --git a/lib/wallets/wallet/impl/epiccash_wallet.dart b/lib/wallets/wallet/impl/epiccash_wallet.dart index b2e5ad3f1..8d9defe77 100644 --- a/lib/wallets/wallet/impl/epiccash_wallet.dart +++ b/lib/wallets/wallet/impl/epiccash_wallet.dart @@ -26,7 +26,6 @@ import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_ import 'package:stackwallet/services/event_bus/global_event_bus.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/default_epicboxes.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/stack_file_system.dart'; @@ -543,7 +542,7 @@ class EpiccashWallet extends Bip39Wallet { } else { try { Logging.instance.log( - "initializeExisting() ${cryptoCurrency.coin.prettyName} wallet", + "initializeExisting() ${cryptoCurrency.prettyName} wallet", level: LogLevel.Info); final config = await _getRealConfig(); @@ -774,7 +773,7 @@ class EpiccashWallet extends Bip39Wallet { WalletSyncStatusChangedEvent( WalletSyncStatus.syncing, walletId, - cryptoCurrency.coin, + cryptoCurrency, ), ); @@ -831,7 +830,7 @@ class EpiccashWallet extends Bip39Wallet { WalletSyncStatusChangedEvent( WalletSyncStatus.synced, walletId, - cryptoCurrency.coin, + cryptoCurrency, ), ); @@ -853,14 +852,14 @@ class EpiccashWallet extends Bip39Wallet { NodeConnectionStatusChangedEvent( NodeConnectionStatus.disconnected, walletId, - cryptoCurrency.coin, + cryptoCurrency, ), ); GlobalEventBus.instance.fire( WalletSyncStatusChangedEvent( WalletSyncStatus.unableToSync, walletId, - cryptoCurrency.coin, + cryptoCurrency, ), ); Logging.instance.log( @@ -1072,7 +1071,7 @@ class EpiccashWallet extends Bip39Wallet { @override Future<bool> pingCheck() async { try { - final node = nodeService.getPrimaryNodeFor(coin: cryptoCurrency.coin); + final node = nodeService.getPrimaryNodeFor(currency: cryptoCurrency); // force unwrap optional as we want connection test to fail if wallet // wasn't initialized or epicbox node was set to null diff --git a/lib/wallets/wallet/impl/ethereum_wallet.dart b/lib/wallets/wallet/impl/ethereum_wallet.dart index a4ad1b341..38b9710e7 100644 --- a/lib/wallets/wallet/impl/ethereum_wallet.dart +++ b/lib/wallets/wallet/impl/ethereum_wallet.dart @@ -16,7 +16,6 @@ import 'package:stackwallet/services/ethereum/ethereum_api.dart'; import 'package:stackwallet/services/event_bus/events/global/updated_in_background_event.dart'; import 'package:stackwallet/services/event_bus/global_event_bus.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart'; import 'package:stackwallet/utilities/eth_commons.dart'; import 'package:stackwallet/utilities/logger.dart'; @@ -239,7 +238,7 @@ class EthereumWallet extends Bip39Wallet with PrivateKeyInterface { if (response.value == null) { Logging.instance.log( - "Failed to refresh transactions for ${cryptoCurrency.coin.prettyName} ${info.name} " + "Failed to refresh transactions for ${cryptoCurrency.prettyName} ${info.name} " "$walletId: ${response.exception}", level: LogLevel.Warning, ); @@ -349,7 +348,7 @@ class EthereumWallet extends Bip39Wallet with PrivateKeyInterface { await mainDB.updateOrPutTransactionV2s(txns); } else { Logging.instance.log( - "Failed to refresh transactions with nonces for ${cryptoCurrency.coin.prettyName} " + "Failed to refresh transactions with nonces for ${cryptoCurrency.prettyName} " "${info.name} $walletId: ${txsResponse.exception}", level: LogLevel.Warning, ); diff --git a/lib/wallets/wallet/impl/firo_wallet.dart b/lib/wallets/wallet/impl/firo_wallet.dart index ea109fe61..d38e99287 100644 --- a/lib/wallets/wallet/impl/firo_wallet.dart +++ b/lib/wallets/wallet/impl/firo_wallet.dart @@ -15,6 +15,7 @@ import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; +import 'package:stackwallet/wallets/crypto_currency/interfaces/electrumx_currency_interface.dart'; import 'package:stackwallet/wallets/isar/models/spark_coin.dart'; import 'package:stackwallet/wallets/isar/models/wallet_info.dart'; import 'package:stackwallet/wallets/models/tx_data.dart'; @@ -25,12 +26,12 @@ import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/spark_interfa const sparkStartBlock = 819300; // (approx 18 Jan 2024) -class FiroWallet extends Bip39HDWallet - with ElectrumXInterface, LelantusInterface, SparkInterface { +class FiroWallet<T extends ElectrumXCurrencyInterface> extends Bip39HDWallet<T> + with ElectrumXInterface<T>, LelantusInterface<T>, SparkInterface<T> { // IMPORTANT: The order of the above mixins matters. // SparkInterface MUST come after LelantusInterface. - FiroWallet(CryptoCurrencyNetwork network) : super(Firo(network)); + FiroWallet(CryptoCurrencyNetwork network) : super(Firo(network) as T); @override int get isarTransactionVersion => 2; @@ -112,7 +113,7 @@ class FiroWallet extends Bip39HDWallet final txn = await electrumXCachedClient.getTransaction( txHash: tx.txid, verbose: true, - coin: info.coin, + cryptoCurrency: info.coin, ); final height = txn["height"] as int?; @@ -146,7 +147,7 @@ class FiroWallet extends Bip39HDWallet tx = await electrumXCachedClient.getTransaction( txHash: txHash["tx_hash"] as String, verbose: true, - coin: info.coin, + cryptoCurrency: info.coin, ); } catch (_) { continue; @@ -379,7 +380,7 @@ class FiroWallet extends Bip39HDWallet } else if (coinbase == null && txid != null && vout != null) { final inputTx = await electrumXCachedClient.getTransaction( txHash: txid, - coin: cryptoCurrency.coin, + cryptoCurrency: cryptoCurrency, ); final prevOutJson = Map<String, dynamic>.from( @@ -603,7 +604,7 @@ class FiroWallet extends Bip39HDWallet if (isRescan) { // clear cache await electrumXCachedClient.clearSharedTransactionCache( - coin: info.coin); + cryptoCurrency: info.coin); // clear blockchain info await mainDB.deleteWalletBlockchainData(walletId); } @@ -613,19 +614,19 @@ class FiroWallet extends Bip39HDWallet final setDataMapFuture = getSetDataMap(latestSetId); final usedSerialNumbersFuture = electrumXCachedClient.getUsedCoinSerials( - coin: info.coin, + cryptoCurrency: info.coin, ); // spark final latestSparkCoinId = await electrumXClient.getSparkLatestCoinId(); final sparkAnonSetFuture = electrumXCachedClient.getSparkAnonymitySet( groupId: latestSparkCoinId.toString(), - coin: info.coin, + cryptoCurrency: info.coin, useOnlyCacheIfNotEmpty: false, ); final sparkUsedCoinTagsFuture = electrumXCachedClient.getSparkUsedCoinsTags( - coin: info.coin, + cryptoCurrency: info.coin, ); // receiving addresses diff --git a/lib/wallets/wallet/impl/litecoin_wallet.dart b/lib/wallets/wallet/impl/litecoin_wallet.dart index a2c6b00c3..a8825d003 100644 --- a/lib/wallets/wallet/impl/litecoin_wallet.dart +++ b/lib/wallets/wallet/impl/litecoin_wallet.dart @@ -9,17 +9,19 @@ import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/wallets/crypto_currency/coins/litecoin.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; +import 'package:stackwallet/wallets/crypto_currency/interfaces/electrumx_currency_interface.dart'; import 'package:stackwallet/wallets/wallet/intermediate/bip39_hd_wallet.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/coin_control_interface.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/ordinals_interface.dart'; -class LitecoinWallet extends Bip39HDWallet - with ElectrumXInterface, CoinControlInterface, OrdinalsInterface { +class LitecoinWallet<T extends ElectrumXCurrencyInterface> + extends Bip39HDWallet<T> + with ElectrumXInterface<T>, CoinControlInterface<T>, OrdinalsInterface<T> { @override int get isarTransactionVersion => 2; - LitecoinWallet(CryptoCurrencyNetwork network) : super(Litecoin(network)); + LitecoinWallet(CryptoCurrencyNetwork network) : super(Litecoin(network) as T); @override FilterOperation? get changeAddressFilterOperation => @@ -91,7 +93,7 @@ class LitecoinWallet extends Bip39HDWallet final tx = await electrumXCachedClient.getTransaction( txHash: txHash["tx_hash"] as String, verbose: true, - coin: cryptoCurrency.coin, + cryptoCurrency: cryptoCurrency, ); // Only tx to list once. @@ -135,7 +137,7 @@ class LitecoinWallet extends Bip39HDWallet final inputTx = await electrumXCachedClient.getTransaction( txHash: txid, - coin: cryptoCurrency.coin, + cryptoCurrency: cryptoCurrency, ); final prevOutJson = Map<String, dynamic>.from( diff --git a/lib/wallets/wallet/impl/namecoin_wallet.dart b/lib/wallets/wallet/impl/namecoin_wallet.dart index c921b34b8..dee5c1d13 100644 --- a/lib/wallets/wallet/impl/namecoin_wallet.dart +++ b/lib/wallets/wallet/impl/namecoin_wallet.dart @@ -8,16 +8,17 @@ import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/wallets/crypto_currency/coins/namecoin.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; +import 'package:stackwallet/wallets/crypto_currency/interfaces/electrumx_currency_interface.dart'; import 'package:stackwallet/wallets/wallet/intermediate/bip39_hd_wallet.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/coin_control_interface.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart'; -class NamecoinWallet extends Bip39HDWallet - with ElectrumXInterface, CoinControlInterface { +class NamecoinWallet<T extends ElectrumXCurrencyInterface> extends Bip39HDWallet<T> + with ElectrumXInterface<T>, CoinControlInterface<T> { @override int get isarTransactionVersion => 2; - NamecoinWallet(CryptoCurrencyNetwork network) : super(Namecoin(network)); + NamecoinWallet(CryptoCurrencyNetwork network) : super(Namecoin(network) as T); @override FilterOperation? get changeAddressFilterOperation => @@ -117,7 +118,7 @@ class NamecoinWallet extends Bip39HDWallet final tx = await electrumXCachedClient.getTransaction( txHash: txHash["tx_hash"] as String, verbose: true, - coin: cryptoCurrency.coin, + cryptoCurrency: cryptoCurrency, ); // Only tx to list once. @@ -159,7 +160,7 @@ class NamecoinWallet extends Bip39HDWallet final inputTx = await electrumXCachedClient.getTransaction( txHash: txid, - coin: cryptoCurrency.coin, + cryptoCurrency: cryptoCurrency, ); final prevOutJson = Map<String, dynamic>.from( diff --git a/lib/wallets/wallet/impl/particl_wallet.dart b/lib/wallets/wallet/impl/particl_wallet.dart index 8c4a12a28..5b9e8f714 100644 --- a/lib/wallets/wallet/impl/particl_wallet.dart +++ b/lib/wallets/wallet/impl/particl_wallet.dart @@ -14,17 +14,19 @@ import 'package:stackwallet/utilities/extensions/impl/uint8_list.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/wallets/crypto_currency/coins/particl.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; +import 'package:stackwallet/wallets/crypto_currency/interfaces/electrumx_currency_interface.dart'; import 'package:stackwallet/wallets/models/tx_data.dart'; import 'package:stackwallet/wallets/wallet/intermediate/bip39_hd_wallet.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/coin_control_interface.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart'; -class ParticlWallet extends Bip39HDWallet - with ElectrumXInterface, CoinControlInterface { +class ParticlWallet<T extends ElectrumXCurrencyInterface> + extends Bip39HDWallet<T> + with ElectrumXInterface<T>, CoinControlInterface<T> { @override int get isarTransactionVersion => 2; - ParticlWallet(CryptoCurrencyNetwork network) : super(Particl(network)); + ParticlWallet(CryptoCurrencyNetwork network) : super(Particl(network) as T); // TODO: double check these filter operations are correct and do not require additional parameters @override @@ -162,7 +164,7 @@ class ParticlWallet extends Bip39HDWallet final tx = await electrumXCachedClient.getTransaction( txHash: txHash["tx_hash"] as String, verbose: true, - coin: cryptoCurrency.coin, + cryptoCurrency: cryptoCurrency, ); // Only tx to list once. @@ -204,7 +206,7 @@ class ParticlWallet extends Bip39HDWallet final inputTx = await electrumXCachedClient.getTransaction( txHash: txid, - coin: cryptoCurrency.coin, + cryptoCurrency: cryptoCurrency, ); final prevOutJson = Map<String, dynamic>.from( diff --git a/lib/wallets/wallet/impl/peercoin_wallet.dart b/lib/wallets/wallet/impl/peercoin_wallet.dart index e08566f45..206b78ed3 100644 --- a/lib/wallets/wallet/impl/peercoin_wallet.dart +++ b/lib/wallets/wallet/impl/peercoin_wallet.dart @@ -8,16 +8,18 @@ import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/wallets/crypto_currency/coins/peercoin.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; +import 'package:stackwallet/wallets/crypto_currency/interfaces/electrumx_currency_interface.dart'; import 'package:stackwallet/wallets/wallet/intermediate/bip39_hd_wallet.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/coin_control_interface.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart'; -class PeercoinWallet extends Bip39HDWallet - with ElectrumXInterface, CoinControlInterface { +class PeercoinWallet<T extends ElectrumXCurrencyInterface> + extends Bip39HDWallet<T> + with ElectrumXInterface<T>, CoinControlInterface<T> { @override int get isarTransactionVersion => 2; - PeercoinWallet(CryptoCurrencyNetwork network) : super(Peercoin(network)); + PeercoinWallet(CryptoCurrencyNetwork network) : super(Peercoin(network) as T); @override FilterOperation? get changeAddressFilterOperation => @@ -123,7 +125,7 @@ class PeercoinWallet extends Bip39HDWallet final tx = await electrumXCachedClient.getTransaction( txHash: txHash["tx_hash"] as String, verbose: true, - coin: cryptoCurrency.coin, + cryptoCurrency: cryptoCurrency, ); // Only tx to list once. @@ -165,7 +167,7 @@ class PeercoinWallet extends Bip39HDWallet final inputTx = await electrumXCachedClient.getTransaction( txHash: txid, - coin: cryptoCurrency.coin, + cryptoCurrency: cryptoCurrency, ); final prevOutJson = Map<String, dynamic>.from( diff --git a/lib/wallets/wallet/impl/solana_wallet.dart b/lib/wallets/wallet/impl/solana_wallet.dart index d2f3582c9..801e7e613 100644 --- a/lib/wallets/wallet/impl/solana_wallet.dart +++ b/lib/wallets/wallet/impl/solana_wallet.dart @@ -16,8 +16,6 @@ import 'package:stackwallet/models/paymint/fee_object_model.dart'; import 'package:stackwallet/services/node_service.dart'; import 'package:stackwallet/services/tor_service.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; -import 'package:stackwallet/utilities/default_nodes.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/wallets/crypto_currency/coins/solana.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; @@ -49,7 +47,7 @@ class SolanaWallet extends Bip39Wallet<Solana> { publicKey: List<int>.empty(), derivationIndex: 0, derivationPath: DerivationPath()..value = _addressDerivationPath, - type: cryptoCurrency.coin.primaryAddressType, + type: cryptoCurrency.primaryAddressType, subType: AddressSubType.receiving, ); return addressStruct; @@ -302,19 +300,19 @@ class SolanaWallet extends Bip39Wallet<Solana> { final newBalance = Balance( total: Amount( rawValue: BigInt.from(balance.value), - fractionDigits: Coin.solana.decimals, + fractionDigits: cryptoCurrency.fractionDigits, ), spendable: Amount( rawValue: BigInt.from(spendableBalance), - fractionDigits: Coin.solana.decimals, + fractionDigits: cryptoCurrency.fractionDigits, ), blockedTotal: Amount( rawValue: BigInt.from(minimumRent), - fractionDigits: Coin.solana.decimals, + fractionDigits: cryptoCurrency.fractionDigits, ), pendingSpendable: Amount( rawValue: BigInt.zero, - fractionDigits: Coin.solana.decimals, + fractionDigits: cryptoCurrency.fractionDigits, ), ); @@ -358,8 +356,8 @@ class SolanaWallet extends Bip39Wallet<Solana> { NodeModel getCurrentNode() { return _solNode ?? NodeService(secureStorageInterface: secureStorageInterface) - .getPrimaryNodeFor(coin: info.coin) ?? - DefaultNodes.getNodeFor(info.coin); + .getPrimaryNodeFor(currency: info.coin) ?? + info.coin.defaultNode; } @override diff --git a/lib/wallets/wallet/impl/tezos_wallet.dart b/lib/wallets/wallet/impl/tezos_wallet.dart index bdf3374a8..8506f7ba5 100644 --- a/lib/wallets/wallet/impl/tezos_wallet.dart +++ b/lib/wallets/wallet/impl/tezos_wallet.dart @@ -9,8 +9,6 @@ import 'package:stackwallet/models/paymint/fee_object_model.dart'; import 'package:stackwallet/services/node_service.dart'; import 'package:stackwallet/services/tor_service.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; -import 'package:stackwallet/utilities/default_nodes.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/extensions/impl/string.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/wallets/api/tezos/tezos_account.dart'; @@ -108,12 +106,14 @@ class TezosWallet extends Bip39Wallet<Tezos> { // print("COUNTER: $counter"); // print("customFee: $customFee"); // } - ({InternetAddress host, int port})? proxyInfo = + final ({InternetAddress host, int port})? proxyInfo = prefs.useTor ? TorService.sharedInstance.getProxyInfo() : null; - final tezartClient = tezart.TezartClient(server, - proxy: proxyInfo != null - ? "socks5://${proxyInfo.host}:${proxyInfo.port};" - : null); + final tezartClient = tezart.TezartClient( + server, + proxy: proxyInfo != null + ? "socks5://${proxyInfo.host}:${proxyInfo.port};" + : null, + ); final opList = await tezartClient.transferOperation( source: sourceKeyStore, @@ -182,7 +182,7 @@ class TezosWallet extends Bip39Wallet<Tezos> { throw Exception("$runtimeType prepareSend requires 1 recipient"); } - Amount sendAmount = txData.amount!; + final Amount sendAmount = txData.amount!; if (sendAmount > info.cachedBalance.spendable) { throw Exception("Insufficient available balance"); @@ -249,7 +249,7 @@ class TezosWallet extends Bip39Wallet<Tezos> { amount: sendAmount, address: txData.recipients!.first.address, isChange: txData.recipients!.first.isChange, - ) + ), ], // fee: fee, fee: Amount( @@ -522,8 +522,8 @@ class TezosWallet extends Bip39Wallet<Tezos> { @override Future<void> updateNode() async { _xtzNode = NodeService(secureStorageInterface: secureStorageInterface) - .getPrimaryNodeFor(coin: info.coin) ?? - DefaultNodes.getNodeFor(info.coin); + .getPrimaryNodeFor(currency: info.coin) ?? + info.coin.defaultNode; await refresh(); } @@ -532,8 +532,8 @@ class TezosWallet extends Bip39Wallet<Tezos> { NodeModel getCurrentNode() { return _xtzNode ?? NodeService(secureStorageInterface: secureStorageInterface) - .getPrimaryNodeFor(coin: info.coin) ?? - DefaultNodes.getNodeFor(info.coin); + .getPrimaryNodeFor(currency: info.coin) ?? + info.coin.defaultNode; } @override @@ -547,7 +547,7 @@ class TezosWallet extends Bip39Wallet<Tezos> { return; } - List<Tuple2<Transaction, Address>> transactions = []; + final List<Tuple2<Transaction, Address>> transactions = []; for (final theTx in txs) { final TransactionType txType; @@ -563,7 +563,7 @@ class TezosWallet extends Bip39Wallet<Tezos> { txType = TransactionType.unknown; } - var transaction = Transaction( + final transaction = Transaction( walletId: walletId, txid: theTx.hash, timestamp: theTx.timestamp, diff --git a/lib/wallets/wallet/intermediate/bip39_hd_wallet.dart b/lib/wallets/wallet/intermediate/bip39_hd_wallet.dart index ffb927713..230d8e8a4 100644 --- a/lib/wallets/wallet/intermediate/bip39_hd_wallet.dart +++ b/lib/wallets/wallet/intermediate/bip39_hd_wallet.dart @@ -66,7 +66,7 @@ abstract class Bip39HDWallet<T extends Bip39HDCurrency> extends Bip39Wallet<T> final address = await _generateAddress( chain: chain, index: index, - derivePathType: DerivePathTypeExt.primaryFor(info.coin), + derivePathType: info.coin.primaryDerivePathType, ); await mainDB.updateOrPutAddresses([address]); @@ -88,7 +88,7 @@ abstract class Bip39HDWallet<T extends Bip39HDCurrency> extends Bip39Wallet<T> final address = await _generateAddress( chain: chain, index: index, - derivePathType: DerivePathTypeExt.primaryFor(info.coin), + derivePathType: info.coin.primaryDerivePathType, ); await mainDB.updateOrPutAddresses([address]); @@ -101,7 +101,7 @@ abstract class Bip39HDWallet<T extends Bip39HDCurrency> extends Bip39Wallet<T> final address = await _generateAddress( chain: 0, // receiving index: 0, // initial index - derivePathType: DerivePathTypeExt.primaryFor(info.coin), + derivePathType: info.coin.primaryDerivePathType, ); await mainDB.updateOrPutAddresses([address]); diff --git a/lib/wallets/wallet/intermediate/bip39_wallet.dart b/lib/wallets/wallet/intermediate/bip39_wallet.dart index 0ab794bdd..13842e0dc 100644 --- a/lib/wallets/wallet/intermediate/bip39_wallet.dart +++ b/lib/wallets/wallet/intermediate/bip39_wallet.dart @@ -6,7 +6,7 @@ import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/mnemonic_inte abstract class Bip39Wallet<T extends Bip39Currency> extends Wallet<T> with MnemonicInterface { - Bip39Wallet(T currency) : super(currency); + Bip39Wallet(super.currency); List<FilterOperation> get standardReceivingAddressFilters => [ FilterCondition.equalTo( diff --git a/lib/wallets/wallet/wallet.dart b/lib/wallets/wallet/wallet.dart index 549bfefb2..a427de15f 100644 --- a/lib/wallets/wallet/wallet.dart +++ b/lib/wallets/wallet/wallet.dart @@ -15,13 +15,30 @@ import 'package:stackwallet/services/event_bus/global_event_bus.dart'; import 'package:stackwallet/services/node_service.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/default_nodes.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/sync_type_enum.dart'; import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/paynym_is_api.dart'; import 'package:stackwallet/utilities/prefs.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/banano.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/bitcoin.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/bitcoin_frost.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/bitcoincash.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/dogecoin.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/ecash.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/epiccash.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/ethereum.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/litecoin.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/monero.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/namecoin.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/nano.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/particl.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/peercoin.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/solana.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/stellar.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/tezos.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/wownero.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/isar/models/wallet_info.dart'; import 'package:stackwallet/wallets/models/tx_data.dart'; @@ -309,78 +326,63 @@ abstract class Wallet<T extends CryptoCurrency> { static Wallet _loadWallet({ required WalletInfo walletInfo, }) { - switch (walletInfo.coin) { - case Coin.banano: - return BananoWallet(CryptoCurrencyNetwork.main); + final net = walletInfo.coin.network; + switch (walletInfo.coin.runtimeType) { + case const (Banano): + return BananoWallet(net); - case Coin.bitcoin: - return BitcoinWallet(CryptoCurrencyNetwork.main); - case Coin.bitcoinTestNet: - return BitcoinWallet(CryptoCurrencyNetwork.test); + case const (Bitcoin): + return BitcoinWallet(net); - case Coin.bitcoinFrost: - return BitcoinFrostWallet(CryptoCurrencyNetwork.main); - case Coin.bitcoinFrostTestNet: - return BitcoinFrostWallet(CryptoCurrencyNetwork.test); + case const (BitcoinFrost): + return BitcoinFrostWallet(net); - case Coin.bitcoincash: - return BitcoincashWallet(CryptoCurrencyNetwork.main); - case Coin.bitcoincashTestnet: - return BitcoincashWallet(CryptoCurrencyNetwork.test); + case const (Bitcoincash): + return BitcoincashWallet(net); - case Coin.dogecoin: + case const (Dogecoin): return DogecoinWallet(CryptoCurrencyNetwork.main); - case Coin.dogecoinTestNet: - return DogecoinWallet(CryptoCurrencyNetwork.test); - case Coin.eCash: + case const (Ecash): return EcashWallet(CryptoCurrencyNetwork.main); - case Coin.epicCash: + case const (Epiccash): return EpiccashWallet(CryptoCurrencyNetwork.main); - case Coin.ethereum: + case const (Ethereum): return EthereumWallet(CryptoCurrencyNetwork.main); - case Coin.firo: + case const (Firo): return FiroWallet(CryptoCurrencyNetwork.main); - case Coin.firoTestNet: - return FiroWallet(CryptoCurrencyNetwork.test); - case Coin.litecoin: + case const (Litecoin): return LitecoinWallet(CryptoCurrencyNetwork.main); - case Coin.litecoinTestNet: - return LitecoinWallet(CryptoCurrencyNetwork.test); - case Coin.monero: + case const (Monero): return MoneroWallet(CryptoCurrencyNetwork.main); - case Coin.namecoin: + case const (Namecoin): return NamecoinWallet(CryptoCurrencyNetwork.main); - case Coin.nano: + case const (Nano): return NanoWallet(CryptoCurrencyNetwork.main); - case Coin.particl: + case const (Particl): return ParticlWallet(CryptoCurrencyNetwork.main); - case Coin.peercoin: + case const (Peercoin): return PeercoinWallet(CryptoCurrencyNetwork.main); - case Coin.peercoinTestNet: - return PeercoinWallet(CryptoCurrencyNetwork.test); - case Coin.solana: + case const (Solana): return SolanaWallet(CryptoCurrencyNetwork.main); - case Coin.stellar: + case const (Stellar): return StellarWallet(CryptoCurrencyNetwork.main); - case Coin.stellarTestnet: - return StellarWallet(CryptoCurrencyNetwork.test); - case Coin.tezos: + case const (Tezos): return TezosWallet(CryptoCurrencyNetwork.main); - case Coin.wownero: + case const (Wownero): return WowneroWallet(CryptoCurrencyNetwork.main); default: @@ -413,7 +415,7 @@ abstract class Wallet<T extends CryptoCurrency> { NodeConnectionStatusChangedEvent( status, walletId, - cryptoCurrency.coin, + cryptoCurrency, ), ); @@ -475,8 +477,8 @@ abstract class Wallet<T extends CryptoCurrency> { } NodeModel getCurrentNode() { - final node = nodeService.getPrimaryNodeFor(coin: cryptoCurrency.coin) ?? - DefaultNodes.getNodeFor(cryptoCurrency.coin); + final node = nodeService.getPrimaryNodeFor(currency: cryptoCurrency) ?? + cryptoCurrency.defaultNode; return node; } @@ -498,7 +500,7 @@ abstract class Wallet<T extends CryptoCurrency> { WalletSyncStatusChangedEvent( WalletSyncStatus.syncing, walletId, - cryptoCurrency.coin, + cryptoCurrency, ), ); @@ -584,7 +586,7 @@ abstract class Wallet<T extends CryptoCurrency> { WalletSyncStatusChangedEvent( WalletSyncStatus.synced, walletId, - cryptoCurrency.coin, + cryptoCurrency, ), ); @@ -607,14 +609,14 @@ abstract class Wallet<T extends CryptoCurrency> { NodeConnectionStatusChangedEvent( NodeConnectionStatus.disconnected, walletId, - cryptoCurrency.coin, + cryptoCurrency, ), ); GlobalEventBus.instance.fire( WalletSyncStatusChangedEvent( WalletSyncStatus.unableToSync, walletId, - cryptoCurrency.coin, + cryptoCurrency, ), ); Logging.instance.log( @@ -637,7 +639,7 @@ abstract class Wallet<T extends CryptoCurrency> { case SyncingType.currentWalletOnly: // Close the subscription for this coin's chain height. // NOTE: This does not work now that the subscription is shared - // await (await ChainHeightServiceManager.getService(cryptoCurrency.coin)) + // await (await ChainHeightServiceManager.getService(cryptoCurrency)) // ?.cancelListen(); case SyncingType.selectedWalletsAtStartup: // Close the subscription if this wallet is not in the list to be synced. @@ -650,7 +652,7 @@ abstract class Wallet<T extends CryptoCurrency> { .walletIdEqualTo(id) .findFirstSync()!; - if (wallet.coin == cryptoCurrency.coin) { + if (wallet.coin == cryptoCurrency) { walletIds.add(id); } } @@ -660,7 +662,7 @@ abstract class Wallet<T extends CryptoCurrency> { if (walletIds.isEmpty) { // NOTE: This does not work now that the subscription is shared // await (await ChainHeightServiceManager.getService( - // cryptoCurrency.coin)) + // cryptoCurrency)) // ?.cancelListen(); } } diff --git a/lib/wallets/wallet/wallet_mixin_interfaces/bcash_interface.dart b/lib/wallets/wallet/wallet_mixin_interfaces/bcash_interface.dart index c94fd15f9..6db46e043 100644 --- a/lib/wallets/wallet/wallet_mixin_interfaces/bcash_interface.dart +++ b/lib/wallets/wallet/wallet_mixin_interfaces/bcash_interface.dart @@ -8,11 +8,13 @@ import 'package:stackwallet/models/isar/models/isar_models.dart'; import 'package:stackwallet/models/signing_data.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; +import 'package:stackwallet/wallets/crypto_currency/interfaces/electrumx_currency_interface.dart'; import 'package:stackwallet/wallets/models/tx_data.dart'; import 'package:stackwallet/wallets/wallet/intermediate/bip39_hd_wallet.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart'; -mixin BCashInterface on Bip39HDWallet, ElectrumXInterface { +mixin BCashInterface<T extends ElectrumXCurrencyInterface> + on Bip39HDWallet<T>, ElectrumXInterface<T> { @override Future<TxData> buildTransaction({ required TxData txData, diff --git a/lib/wallets/wallet/wallet_mixin_interfaces/cash_fusion_interface.dart b/lib/wallets/wallet/wallet_mixin_interfaces/cash_fusion_interface.dart index 1a7d424a2..a4395ea7f 100644 --- a/lib/wallets/wallet/wallet_mixin_interfaces/cash_fusion_interface.dart +++ b/lib/wallets/wallet/wallet_mixin_interfaces/cash_fusion_interface.dart @@ -11,16 +11,19 @@ import 'package:stackwallet/models/isar/models/blockchain_data/transaction.dart' import 'package:stackwallet/models/isar/models/blockchain_data/utxo.dart'; import 'package:stackwallet/pages_desktop_specific/cashfusion/sub_widgets/fusion_dialog.dart'; import 'package:stackwallet/services/fusion_tor_service.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/stack_file_system.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/bitcoincash.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/ecash.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; +import 'package:stackwallet/wallets/crypto_currency/interfaces/electrumx_currency_interface.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/coin_control_interface.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart'; const String kReservedFusionAddress = "reserved_fusion_address"; -final kFusionServerInfoDefaults = Map<Coin, FusionInfo>.unmodifiable(const { - Coin.bitcoincash: FusionInfo( +final kFusionServerInfoDefaults = Map<String, FusionInfo>.unmodifiable({ + Bitcoincash(CryptoCurrencyNetwork.main).identifier: const FusionInfo( host: "fusion.servo.cash", port: 8789, ssl: true, @@ -29,7 +32,7 @@ final kFusionServerInfoDefaults = Map<Coin, FusionInfo>.unmodifiable(const { // ssl: false, rounds: 0, // 0 is continuous ), - Coin.bitcoincashTestnet: FusionInfo( + Bitcoincash(CryptoCurrencyNetwork.test).identifier: const FusionInfo( host: "fusion.servo.cash", port: 8789, ssl: true, @@ -38,7 +41,7 @@ final kFusionServerInfoDefaults = Map<Coin, FusionInfo>.unmodifiable(const { // ssl: false, rounds: 0, // 0 is continuous ), - Coin.eCash: FusionInfo( + Ecash(CryptoCurrencyNetwork.main).identifier: const FusionInfo( host: "fusion.tokamak.cash", port: 8788, ssl: true, @@ -109,7 +112,8 @@ class FusionInfo { } } -mixin CashFusionInterface on CoinControlInterface, ElectrumXInterface { +mixin CashFusionInterface<T extends ElectrumXCurrencyInterface> + on CoinControlInterface<T>, ElectrumXInterface<T> { final _torService = FusionTorService.sharedInstance; // setting values on this should notify any listeners (the GUI) @@ -307,7 +311,7 @@ mixin CashFusionInterface on CoinControlInterface, ElectrumXInterface { final futures = txidList.map( (e) => electrumXCachedClient.getTransaction( txHash: e, - coin: info.coin, + cryptoCurrency: info.coin, ), ); @@ -589,7 +593,7 @@ mixin CashFusionInterface on CoinControlInterface, ElectrumXInterface { checkUtxoExists: _checkUtxoExists, getTransactionJson: (String txid) async => await electrumXCachedClient.getTransaction( - coin: info.coin, + cryptoCurrency: info.coin, txHash: txid, ), getPrivateKeyForPubKey: _getPrivateKeyForPubKey, diff --git a/lib/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart b/lib/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart index 026e9f5fc..1ce6c7717 100644 --- a/lib/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart +++ b/lib/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart @@ -14,21 +14,21 @@ import 'package:stackwallet/models/isar/models/isar_models.dart'; import 'package:stackwallet/models/paymint/fee_object_model.dart'; import 'package:stackwallet/models/signing_data.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart'; import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart'; import 'package:stackwallet/utilities/extensions/extensions.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/paynym_is_api.dart'; import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; -import 'package:stackwallet/wallets/crypto_currency/intermediate/bip39_hd_currency.dart'; +import 'package:stackwallet/wallets/crypto_currency/interfaces/electrumx_currency_interface.dart'; import 'package:stackwallet/wallets/models/tx_data.dart'; import 'package:stackwallet/wallets/wallet/impl/bitcoin_wallet.dart'; import 'package:stackwallet/wallets/wallet/impl/peercoin_wallet.dart'; import 'package:stackwallet/wallets/wallet/intermediate/bip39_hd_wallet.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/paynym_interface.dart'; -mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> { +mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface> + on Bip39HDWallet<T> { late ElectrumXClient electrumXClient; late CachedElectrumXClient electrumXCachedClient; @@ -43,9 +43,11 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> { } try { - _serverVersion ??= _parseServerVersion((await electrumXClient - .getServerFeatures() - .timeout(const Duration(seconds: 2)))["server_version"] as String); + _serverVersion ??= _parseServerVersion( + (await electrumXClient + .getServerFeatures() + .timeout(const Duration(seconds: 2)))["server_version"] as String, + ); } catch (_) { // ignore failure as it doesn't matter } @@ -133,22 +135,30 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> { // don't care about sorting if using all utxos if (!coinControl) { // sort spendable by age (oldest first) - spendableOutputs.sort((a, b) => (b.blockTime ?? currentChainHeight) - .compareTo((a.blockTime ?? currentChainHeight))); + spendableOutputs.sort( + (a, b) => (b.blockTime ?? currentChainHeight) + .compareTo((a.blockTime ?? currentChainHeight)), + ); // Null check operator changed to null assignment in order to resolve a // `Null check operator used on a null value` error. currentChainHeight // used in order to sort these unconfirmed outputs as the youngest, but we // could just as well use currentChainHeight + 1. } - Logging.instance.log("spendableOutputs.length: ${spendableOutputs.length}", - level: LogLevel.Info); - Logging.instance.log("availableOutputs.length: ${availableOutputs.length}", - level: LogLevel.Info); + Logging.instance.log( + "spendableOutputs.length: ${spendableOutputs.length}", + level: LogLevel.Info, + ); + Logging.instance.log( + "availableOutputs.length: ${availableOutputs.length}", + level: LogLevel.Info, + ); Logging.instance .log("spendableOutputs: $spendableOutputs", level: LogLevel.Info); - Logging.instance.log("spendableSatoshiValue: $spendableSatoshiValue", - level: LogLevel.Info); + Logging.instance.log( + "spendableSatoshiValue: $spendableSatoshiValue", + level: LogLevel.Info, + ); Logging.instance .log("satoshiAmountToSend: $satoshiAmountToSend", level: LogLevel.Info); // If the amount the user is trying to send is smaller than the amount that they have spendable, @@ -299,7 +309,7 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> { [recipientAddress, (await getCurrentChangeAddress())!.value], [ satoshiAmountToSend, - max(0, satoshisBeingUsed - satoshiAmountToSend - 1) + max(0, satoshisBeingUsed - satoshiAmountToSend - 1), ], ), ), @@ -358,13 +368,18 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> { Logging.instance.log('2 outputs in tx', level: LogLevel.Info); Logging.instance .log('Input size: $satoshisBeingUsed', level: LogLevel.Info); - Logging.instance.log('Recipient output size: $satoshiAmountToSend', - level: LogLevel.Info); - Logging.instance.log('Change Output Size: $changeOutputSize', - level: LogLevel.Info); Logging.instance.log( - 'Difference (fee being paid): $feeBeingPaid sats', - level: LogLevel.Info); + 'Recipient output size: $satoshiAmountToSend', + level: LogLevel.Info, + ); + Logging.instance.log( + 'Change Output Size: $changeOutputSize', + level: LogLevel.Info, + ); + Logging.instance.log( + 'Difference (fee being paid): $feeBeingPaid sats', + level: LogLevel.Info, + ); Logging.instance .log('Estimated fee: $feeForTwoOutputs', level: LogLevel.Info); @@ -386,19 +401,26 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> { satoshisBeingUsed - satoshiAmountToSend - changeOutputSize; recipientsAmtArray.removeLast(); recipientsAmtArray.add(changeOutputSize); - Logging.instance.log('Adjusted Input size: $satoshisBeingUsed', - level: LogLevel.Info); Logging.instance.log( - 'Adjusted Recipient output size: $satoshiAmountToSend', - level: LogLevel.Info); + 'Adjusted Input size: $satoshisBeingUsed', + level: LogLevel.Info, + ); Logging.instance.log( - 'Adjusted Change Output Size: $changeOutputSize', - level: LogLevel.Info); + 'Adjusted Recipient output size: $satoshiAmountToSend', + level: LogLevel.Info, + ); Logging.instance.log( - 'Adjusted Difference (fee being paid): $feeBeingPaid sats', - level: LogLevel.Info); - Logging.instance.log('Adjusted Estimated fee: $feeForTwoOutputs', - level: LogLevel.Info); + 'Adjusted Change Output Size: $changeOutputSize', + level: LogLevel.Info, + ); + Logging.instance.log( + 'Adjusted Difference (fee being paid): $feeBeingPaid sats', + level: LogLevel.Info, + ); + Logging.instance.log( + 'Adjusted Estimated fee: $feeForTwoOutputs', + level: LogLevel.Info, + ); txn = await buildTransaction( utxoSigningData: utxoSigningData, txData: txData.copyWith( @@ -423,11 +445,14 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> { Logging.instance.log('1 output in tx', level: LogLevel.Info); Logging.instance .log('Input size: $satoshisBeingUsed', level: LogLevel.Info); - Logging.instance.log('Recipient output size: $satoshiAmountToSend', - level: LogLevel.Info); Logging.instance.log( - 'Difference (fee being paid): ${satoshisBeingUsed - satoshiAmountToSend} sats', - level: LogLevel.Info); + 'Recipient output size: $satoshiAmountToSend', + level: LogLevel.Info, + ); + Logging.instance.log( + 'Difference (fee being paid): ${satoshisBeingUsed - satoshiAmountToSend} sats', + level: LogLevel.Info, + ); Logging.instance .log('Estimated fee: $feeForOneOutput', level: LogLevel.Info); final txn = await buildTransaction( @@ -455,11 +480,14 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> { Logging.instance.log('1 output in tx', level: LogLevel.Info); Logging.instance .log('Input size: $satoshisBeingUsed', level: LogLevel.Info); - Logging.instance.log('Recipient output size: $satoshiAmountToSend', - level: LogLevel.Info); Logging.instance.log( - 'Difference (fee being paid): ${satoshisBeingUsed - satoshiAmountToSend} sats', - level: LogLevel.Info); + 'Recipient output size: $satoshiAmountToSend', + level: LogLevel.Info, + ); + Logging.instance.log( + 'Difference (fee being paid): ${satoshisBeingUsed - satoshiAmountToSend} sats', + level: LogLevel.Info, + ); Logging.instance .log('Estimated fee: $feeForOneOutput', level: LogLevel.Info); final txn = await buildTransaction( @@ -487,11 +515,14 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> { Logging.instance.log('1 output in tx', level: LogLevel.Info); Logging.instance .log('Input size: $satoshisBeingUsed', level: LogLevel.Info); - Logging.instance.log('Recipient output size: $satoshiAmountToSend', - level: LogLevel.Info); Logging.instance.log( - 'Fee being paid: ${satoshisBeingUsed - satoshiAmountToSend} sats', - level: LogLevel.Info); + 'Recipient output size: $satoshiAmountToSend', + level: LogLevel.Info, + ); + Logging.instance.log( + 'Fee being paid: ${satoshisBeingUsed - satoshiAmountToSend} sats', + level: LogLevel.Info, + ); Logging.instance .log('Estimated fee: $feeForOneOutput', level: LogLevel.Info); final txn = await buildTransaction( @@ -515,8 +546,9 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> { // pay for the transaction fee. Ideally, at this stage, we should check if the user has any // additional outputs they're able to spend and then recalculate fees. Logging.instance.log( - 'Cannot pay tx fee - checking for more outputs and trying again', - level: LogLevel.Warning); + 'Cannot pay tx fee - checking for more outputs and trying again', + level: LogLevel.Warning, + ); // try adding more outputs if (spendableOutputs.length > inputsBeingConsumed) { return coinSelection( @@ -589,7 +621,8 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> { if (keys == null) { throw Exception( - "Failed to fetch signing data. Local db corrupt. Rescan wallet."); + "Failed to fetch signing data. Local db corrupt. Rescan wallet.", + ); } sd.keyPair = keys; @@ -762,8 +795,10 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> { ); } } catch (e, s) { - Logging.instance.log("Caught exception while signing transaction: $e\n$s", - level: LogLevel.Error); + Logging.instance.log( + "Caught exception while signing transaction: $e\n$s", + level: LogLevel.Error, + ); rethrow; } @@ -799,8 +834,9 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> { ); } catch (e, s) { Logging.instance.log( - "Exception rethrown in fetchChainHeight\nError: $e\nStack trace: $s", - level: LogLevel.Error); + "Exception rethrown in fetchChainHeight\nError: $e\nStack trace: $s", + level: LogLevel.Error, + ); // completer.completeError(e, s); // return Future.error(e, s); rethrow; @@ -819,9 +855,10 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> { }) async { try { final response = await electrumXClient.getBatchHistory( - args: addresses - .map((e) => [cryptoCurrency.addressToScriptHash(address: e)]) - .toList(growable: false)); + args: addresses + .map((e) => [cryptoCurrency.addressToScriptHash(address: e)]) + .toList(growable: false), + ); final List<int> result = []; for (final entry in response) { @@ -830,8 +867,9 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> { return result; } catch (e, s) { Logging.instance.log( - "Exception rethrown in _getBatchTxCount(address: $addresses: $e\n$s", - level: LogLevel.Error); + "Exception rethrown in _getBatchTxCount(address: $addresses: $e\n$s", + level: LogLevel.Error, + ); rethrow; } } @@ -850,14 +888,16 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> { Future<void> updateElectrumX() async { final failovers = nodeService - .failoverNodesFor(coin: cryptoCurrency.coin) - .map((e) => ElectrumXNode( - address: e.host, - port: e.port, - name: e.name, - id: e.id, - useSSL: e.useSSL, - )) + .failoverNodesFor(currency: cryptoCurrency) + .map( + (e) => ElectrumXNode( + address: e.host, + port: e.port, + name: e.name, + id: e.id, + useSSL: e.useSSL, + ), + ) .toList(); final newNode = await _getCurrentElectrumXNode(); @@ -899,8 +939,9 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> { gapCounter < cryptoCurrency.maxUnusedAddressGap; index += txCountBatchSize) { Logging.instance.log( - "index: $index, \t GapCounter $chain ${type.name}: $gapCounter", - level: LogLevel.Info); + "index: $index, \t GapCounter $chain ${type.name}: $gapCounter", + level: LogLevel.Info, + ); final List<String> txCountCallArgs = []; @@ -979,8 +1020,9 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> { gapCounter < cryptoCurrency.maxUnusedAddressGap; index++) { Logging.instance.log( - "index: $index, \t GapCounter chain=$chain ${type.name}: $gapCounter", - level: LogLevel.Info); + "index: $index, \t GapCounter chain=$chain ${type.name}: $gapCounter", + level: LogLevel.Info, + ); final derivePath = cryptoCurrency.constructDerivePath( derivePathType: type, @@ -1107,7 +1149,7 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> { final txn = await electrumXCachedClient.getTransaction( txHash: jsonUTXO["tx_hash"] as String, verbose: true, - coin: cryptoCurrency.coin, + cryptoCurrency: cryptoCurrency, ); final vout = jsonUTXO["tx_pos"] as int; @@ -1194,15 +1236,15 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> { numberOfBlocksSlow: s, fast: Amount.fromDecimal( fast, - fractionDigits: info.coin.decimals, + fractionDigits: info.coin.fractionDigits, ).raw.toInt(), medium: Amount.fromDecimal( medium, - fractionDigits: info.coin.decimals, + fractionDigits: info.coin.fractionDigits, ).raw.toInt(), slow: Amount.fromDecimal( slow, - fractionDigits: info.coin.decimals, + fractionDigits: info.coin.fractionDigits, ).raw.toInt(), ); @@ -1235,14 +1277,14 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> { Amount runningBalance = Amount( rawValue: BigInt.zero, - fractionDigits: info.coin.decimals, + fractionDigits: info.coin.fractionDigits, ); int inputCount = 0; for (final output in utxos) { if (!output.isBlocked) { runningBalance += Amount( rawValue: BigInt.from(output.value), - fractionDigits: info.coin.decimals, + fractionDigits: info.coin.fractionDigits, ); inputCount++; if (runningBalance > amount) { @@ -1366,7 +1408,8 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> { if (isRescan) { // clear cache await electrumXCachedClient.clearSharedTransactionCache( - coin: info.coin); + cryptoCurrency: info.coin, + ); // clear blockchain info await mainDB.deleteWalletBlockchainData(walletId); } @@ -1459,12 +1502,16 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> { } // remove extra addresses to help minimize risk of creating a large gap - addressesToStore.removeWhere((e) => - e.subType == AddressSubType.change && - e.derivationIndex > highestChangeIndexWithHistory); - addressesToStore.removeWhere((e) => - e.subType == AddressSubType.receiving && - e.derivationIndex > highestReceivingIndexWithHistory); + addressesToStore.removeWhere( + (e) => + e.subType == AddressSubType.change && + e.derivationIndex > highestChangeIndexWithHistory, + ); + addressesToStore.removeWhere( + (e) => + e.subType == AddressSubType.receiving && + e.derivationIndex > highestReceivingIndexWithHistory, + ); await mainDB.updateOrPutAddresses(addressesToStore); @@ -1512,8 +1559,9 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> { unawaited(refresh()); } catch (e, s) { Logging.instance.log( - "Exception rethrown from electrumx_mixin recover(): $e\n$s", - level: LogLevel.Info); + "Exception rethrown from electrumx_mixin recover(): $e\n$s", + level: LogLevel.Info, + ); rethrow; } @@ -1609,8 +1657,10 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> { return await updateSentCachedTxData(txData: txData); } catch (e, s) { - Logging.instance.log("Exception rethrown from confirmSend(): $e\n$s", - level: LogLevel.Error); + Logging.instance.log( + "Exception rethrown from confirmSend(): $e\n$s", + level: LogLevel.Error, + ); rethrow; } } @@ -1644,7 +1694,8 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> { if (result.fee!.raw.toInt() < result.vSize!) { throw Exception( - "Error in fee calculation: Transaction fee cannot be less than vSize"); + "Error in fee calculation: Transaction fee cannot be less than vSize", + ); } return result; @@ -1700,8 +1751,10 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> { throw ArgumentError("Invalid fee rate argument provided!"); } } catch (e, s) { - Logging.instance.log("Exception rethrown from prepareSend(): $e\n$s", - level: LogLevel.Error); + Logging.instance.log( + "Exception rethrown from prepareSend(): $e\n$s", + level: LogLevel.Error, + ); rethrow; } } @@ -1777,7 +1830,7 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> { return Amount( rawValue: available, - fractionDigits: info.coin.decimals, + fractionDigits: info.coin.fractionDigits, ) - estimatedFee; } diff --git a/lib/wallets/wallet/wallet_mixin_interfaces/lelantus_interface.dart b/lib/wallets/wallet/wallet_mixin_interfaces/lelantus_interface.dart index ce8c5064d..f182c8ca1 100644 --- a/lib/wallets/wallet/wallet_mixin_interfaces/lelantus_interface.dart +++ b/lib/wallets/wallet/wallet_mixin_interfaces/lelantus_interface.dart @@ -16,15 +16,17 @@ import 'package:stackwallet/utilities/format.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/wallets/api/lelantus_ffi_wrapper.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; +import 'package:stackwallet/wallets/crypto_currency/interfaces/electrumx_currency_interface.dart'; import 'package:stackwallet/wallets/models/tx_data.dart'; import 'package:stackwallet/wallets/wallet/intermediate/bip39_hd_wallet.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart'; import 'package:tuple/tuple.dart'; -mixin LelantusInterface on Bip39HDWallet, ElectrumXInterface { +mixin LelantusInterface<T extends ElectrumXCurrencyInterface> + on Bip39HDWallet<T>, ElectrumXInterface<T> { Future<Amount> estimateFeeForLelantus(Amount amount) async { final lelantusEntries = await _getLelantusEntry(); - int spendAmount = amount.raw.toInt(); + final int spendAmount = amount.raw.toInt(); if (spendAmount == 0 || lelantusEntries.isEmpty) { return Amount( rawValue: BigInt.from(LelantusFeeData(0, 0, []).fee), @@ -52,10 +54,12 @@ mixin LelantusInterface on Bip39HDWallet, ElectrumXInterface { .filter() .isUsedEqualTo(false) .not() - .group((q) => q - .valueEqualTo("0") - .or() - .anonymitySetIdEqualTo(LelantusFfiWrapper.ANONYMITY_SET_EMPTY_ID)) + .group( + (q) => q + .valueEqualTo("0") + .or() + .anonymitySetIdEqualTo(LelantusFfiWrapper.ANONYMITY_SET_EMPTY_ID), + ) .findAll(); final root = await getRootHDNode(); @@ -156,12 +160,15 @@ mixin LelantusInterface on Bip39HDWallet, ElectrumXInterface { // fee should never be less than vSize sanity check if (result.fee!.raw.toInt() < result.vSize!) { throw Exception( - "Error in fee calculation: Transaction fee cannot be less than vSize"); + "Error in fee calculation: Transaction fee cannot be less than vSize", + ); } return result; } catch (e, s) { - Logging.instance.log("Exception rethrown in firo prepareSend(): $e\n$s", - level: LogLevel.Error); + Logging.instance.log( + "Exception rethrown in firo prepareSend(): $e\n$s", + level: LogLevel.Error, + ); rethrow; } } @@ -316,17 +323,17 @@ mixin LelantusInterface on Bip39HDWallet, ElectrumXInterface { } Future<List<Map<String, dynamic>>> fastFetch(List<String> allTxHashes) async { - List<Map<String, dynamic>> allTransactions = []; + final List<Map<String, dynamic>> allTransactions = []; const futureLimit = 30; - List<Future<Map<String, dynamic>>> transactionFutures = []; + final List<Future<Map<String, dynamic>>> transactionFutures = []; int currentFutureCount = 0; for (final txHash in allTxHashes) { - Future<Map<String, dynamic>> transactionFuture = + final Future<Map<String, dynamic>> transactionFuture = electrumXCachedClient.getTransaction( txHash: txHash, verbose: true, - coin: cryptoCurrency.coin, + cryptoCurrency: cryptoCurrency, ); transactionFutures.add(transactionFuture); currentFutureCount++; @@ -362,8 +369,8 @@ mixin LelantusInterface on Bip39HDWallet, ElectrumXInterface { List<String> transactions, ) async { try { - Map<Address, Transaction> txs = {}; - List<Map<String, dynamic>> allTransactions = + final Map<Address, Transaction> txs = {}; + final List<Map<String, dynamic>> allTransactions = await fastFetch(transactions); for (int i = 0; i < allTransactions.length; i++) { @@ -426,16 +433,18 @@ mixin LelantusInterface on Bip39HDWallet, ElectrumXInterface { txs[address] = txn; } catch (e, s) { Logging.instance.log( - "Exception caught in getJMintTransactions(): $e\n$s", - level: LogLevel.Info); + "Exception caught in getJMintTransactions(): $e\n$s", + level: LogLevel.Info, + ); rethrow; } } return txs; } catch (e, s) { Logging.instance.log( - "Exception rethrown in getJMintTransactions(): $e\n$s", - level: LogLevel.Info); + "Exception rethrown in getJMintTransactions(): $e\n$s", + level: LogLevel.Info, + ); rethrow; } } @@ -445,25 +454,26 @@ mixin LelantusInterface on Bip39HDWallet, ElectrumXInterface { final latestSetId = await electrumXClient.getLelantusLatestCoinId(); final List<Map<String, dynamic>> sets = []; - List<Future<Map<String, dynamic>>> anonFutures = []; + final List<Future<Map<String, dynamic>>> anonFutures = []; for (int i = 1; i <= latestSetId; i++) { final set = electrumXCachedClient.getAnonymitySet( groupId: "$i", - coin: info.coin, + cryptoCurrency: info.coin, ); anonFutures.add(set); } await Future.wait(anonFutures); for (int i = 1; i <= latestSetId; i++) { - Map<String, dynamic> set = (await anonFutures[i - 1]); + final Map<String, dynamic> set = (await anonFutures[i - 1]); set["setId"] = i; sets.add(set); } return sets; } catch (e, s) { Logging.instance.log( - "Exception rethrown from refreshAnonymitySets: $e\n$s", - level: LogLevel.Error); + "Exception rethrown from refreshAnonymitySets: $e\n$s", + level: LogLevel.Error, + ); rethrow; } } @@ -497,7 +507,7 @@ mixin LelantusInterface on Bip39HDWallet, ElectrumXInterface { final usedSerialNumbersSet = (await electrumXCachedClient.getUsedCoinSerials( - coin: info.coin, + cryptoCurrency: info.coin, )) .toSet(); @@ -598,10 +608,10 @@ mixin LelantusInterface on Bip39HDWallet, ElectrumXInterface { // TODO: [prio=high] shouldn't these be v2? If it doesn't matter than we can get rid of this logic // Edit the receive transactions with the mint fees. - List<Transaction> editedTransactions = []; + final List<Transaction> editedTransactions = []; for (final coin in result.lelantusCoins) { - String txid = coin.txid; + final String txid = coin.txid; Transaction? tx; try { tx = txns.firstWhere((e) => e.txid == txid); @@ -614,7 +624,7 @@ mixin LelantusInterface on Bip39HDWallet, ElectrumXInterface { continue; } - List<Transaction> inputTxns = []; + final List<Transaction> inputTxns = []; for (final input in tx.inputs) { Transaction? inputTx; try { @@ -635,8 +645,8 @@ mixin LelantusInterface on Bip39HDWallet, ElectrumXInterface { continue; } - int mintFee = tx.fee; - int sharedFee = mintFee ~/ inputTxns.length; + final int mintFee = tx.fee; + final int sharedFee = mintFee ~/ inputTxns.length; for (final inputTx in inputTxns) { final edited = Transaction( walletId: inputTx.walletId, @@ -665,7 +675,7 @@ mixin LelantusInterface on Bip39HDWallet, ElectrumXInterface { } // Logging.instance.log(editedTransactions, addToDebugMessagesDB: false); - Map<String, Transaction> transactionMap = {}; + final Map<String, Transaction> transactionMap = {}; for (final e in txns) { transactionMap[e.txid] = e; } @@ -676,10 +686,12 @@ mixin LelantusInterface on Bip39HDWallet, ElectrumXInterface { transactionMap[tx.txid] = tx; } - transactionMap.removeWhere((key, value) => - result.lelantusCoins.any((element) => element.txid == key) || - ((value.height == -1 || value.height == null) && - !value.isConfirmed(currentHeight, cryptoCurrency.minConfirms))); + transactionMap.removeWhere( + (key, value) => + result.lelantusCoins.any((element) => element.txid == key) || + ((value.height == -1 || value.height == null) && + !value.isConfirmed(currentHeight, cryptoCurrency.minConfirms)), + ); try { await mainDB.isar.writeTxn(() async { @@ -694,7 +706,7 @@ mixin LelantusInterface on Bip39HDWallet, ElectrumXInterface { throw Exception("e=$e & s=$s"); } - Map<String, Tuple2<Address?, Transaction>> data = {}; + final Map<String, Tuple2<Address?, Transaction>> data = {}; for (final entry in transactionMap.entries) { data[entry.key] = Tuple2(entry.value.address.value, entry.value); @@ -730,9 +742,12 @@ mixin LelantusInterface on Bip39HDWallet, ElectrumXInterface { value.item2.outputs.where((_) => true).toList(growable: false); final ins = value.item2.inputs.where((_) => true).toList(growable: false); - txnsData.add(Tuple2( + txnsData.add( + Tuple2( value.item2.copyWith(inputs: ins, outputs: outs).item1, - transactionAddress)); + transactionAddress, + ), + ); } await mainDB.addNewTransactionData(txnsData, walletId); @@ -827,7 +842,7 @@ mixin LelantusInterface on Bip39HDWallet, ElectrumXInterface { for (var mintsElement in txData.mintsMapLelantus!) { Logging.instance.log("using $mintsElement", level: LogLevel.Info); - Uint8List mintu8 = + final Uint8List mintu8 = Format.stringToUint8List(mintsElement['script'] as String); txb.addOutput(mintu8, mintsElement['value'] as int); } @@ -843,12 +858,12 @@ mixin LelantusInterface on Bip39HDWallet, ElectrumXInterface { witnessValue: signingData[i].utxo.value, ); } - var incomplete = txb.buildIncomplete(); - var txId = incomplete.getId(); - var txHex = incomplete.toHex(); - int fee = amount - incomplete.outs[0].value!; + final incomplete = txb.buildIncomplete(); + final txId = incomplete.getId(); + final txHex = incomplete.toHex(); + final int fee = amount - incomplete.outs[0].value!; - var builtHex = txb.build(); + final builtHex = txb.build(); return txData.copyWith( recipients: [ @@ -859,7 +874,7 @@ mixin LelantusInterface on Bip39HDWallet, ElectrumXInterface { ), address: "no address for lelantus mints", isChange: false, - ) + ), ], vSize: builtHex.virtualSize(), txid: txId, @@ -880,14 +895,14 @@ mixin LelantusInterface on Bip39HDWallet, ElectrumXInterface { // "value": amount - fee, // "fees": Amount( // rawValue: BigInt.from(fee), - // fractionDigits: coin.decimals, + // fractionDigits: coin.fractionDigits, // ).decimal.toDouble(), // "height": height, // "txType": "Sent", // "confirmed_status": false, // "amount": Amount( // rawValue: BigInt.from(amount), - // fractionDigits: coin.decimals, + // fractionDigits: coin.fractionDigits, // ).decimal.toDouble(), // "timestamp": DateTime.now().millisecondsSinceEpoch ~/ 1000, // "subType": "mint", @@ -908,7 +923,9 @@ mixin LelantusInterface on Bip39HDWallet, ElectrumXInterface { // Build list of spendable outputs and totaling their satoshi amount for (var i = 0; i < availableOutputs.length; i++) { if (availableOutputs[i].isConfirmed( - currentChainHeight, cryptoCurrency.minConfirms) == + currentChainHeight, + cryptoCurrency.minConfirms, + ) == true && !(availableOutputs[i].isCoinbase && availableOutputs[i].getConfirmations(currentChainHeight) <= @@ -938,8 +955,9 @@ mixin LelantusInterface on Bip39HDWallet, ElectrumXInterface { for (var element in value.inputs) { if (lelantusCoins.any((e) => e.txid == value.txid) && spendableOutputs.firstWhere( - (output) => output?.txid == element.txid, - orElse: () => null) != + (output) => output?.txid == element.txid, + orElse: () => null, + ) != null) { spendableOutputs .removeWhere((output) => output!.txid == element.txid); @@ -954,7 +972,7 @@ mixin LelantusInterface on Bip39HDWallet, ElectrumXInterface { } int satoshisBeingUsed = 0; - Set<UTXO> utxoObjectsToUse = {}; + final Set<UTXO> utxoObjectsToUse = {}; for (var i = 0; i < spendableOutputs.length; i++) { final spendable = spendableOutputs[i]; @@ -964,7 +982,7 @@ mixin LelantusInterface on Bip39HDWallet, ElectrumXInterface { } } - var mintsWithoutFee = await _createMintsFromAmount(satoshisBeingUsed); + final mintsWithoutFee = await _createMintsFromAmount(satoshisBeingUsed); TxData txData = await buildMintTransaction( txData: TxData( @@ -1005,7 +1023,8 @@ mixin LelantusInterface on Bip39HDWallet, ElectrumXInterface { Future<List<Map<String, dynamic>>> _createMintsFromAmount(int total) async { if (total > LelantusFfiWrapper.MINT_LIMIT) { throw Exception( - "Lelantus mints of more than 5001 are currently disabled"); + "Lelantus mints of more than 5001 are currently disabled", + ); } int tmpTotal = total; @@ -1075,10 +1094,11 @@ mixin LelantusInterface on Bip39HDWallet, ElectrumXInterface { if (!isUsedMintTag) { final mintValue = min( - tmpTotal, - (isTestnet - ? LelantusFfiWrapper.MINT_LIMIT_TESTNET - : LelantusFfiWrapper.MINT_LIMIT)); + tmpTotal, + (isTestnet + ? LelantusFfiWrapper.MINT_LIMIT_TESTNET + : LelantusFfiWrapper.MINT_LIMIT), + ); final mint = await LelantusFfiWrapper.getMintScript( amount: Amount( rawValue: BigInt.from(mintValue), diff --git a/lib/wallets/wallet/wallet_mixin_interfaces/nano_interface.dart b/lib/wallets/wallet/wallet_mixin_interfaces/nano_interface.dart index dd52da8de..f787b91f7 100644 --- a/lib/wallets/wallet/wallet_mixin_interfaces/nano_interface.dart +++ b/lib/wallets/wallet/wallet_mixin_interfaces/nano_interface.dart @@ -13,8 +13,6 @@ import 'package:stackwallet/services/nano_api.dart'; import 'package:stackwallet/services/node_service.dart'; import 'package:stackwallet/services/tor_service.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; -import 'package:stackwallet/utilities/default_nodes.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/extensions/impl/string.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/wallets/crypto_currency/intermediate/nano_currency.dart'; @@ -81,7 +79,7 @@ mixin NanoInterface<T extends NanoCurrency> on Bip39Wallet<T> { publicKey: publicKey.toUint8ListFromHex, derivationIndex: 0, derivationPath: null, - type: cryptoCurrency.coin.primaryAddressType, + type: cryptoCurrency.primaryAddressType, subType: AddressSubType.receiving, ); } @@ -138,7 +136,7 @@ mixin NanoInterface<T extends NanoCurrency> on Bip39Wallet<T> { final BigInt txAmount = BigInt.parse(amountRaw); final BigInt balanceAfterTx = currentBalance + txAmount; - String frontier = infoData["frontier"].toString(); + final String frontier = infoData["frontier"].toString(); String representative = infoData["representative"].toString(); if (openBlock) { @@ -153,7 +151,7 @@ mixin NanoInterface<T extends NanoCurrency> on Bip39Wallet<T> { NanoAccounts.createAccount(NanoAccountType.BANANO, blockHash); // construct the receive block: - Map<String, String> receiveBlock = { + final Map<String, String> receiveBlock = { "type": "state", "account": publicAddress, "previous": openBlock @@ -300,8 +298,8 @@ mixin NanoInterface<T extends NanoCurrency> on Bip39Wallet<T> { @override Future<void> updateNode() async { _cachedNode = NodeService(secureStorageInterface: secureStorageInterface) - .getPrimaryNodeFor(coin: info.coin) ?? - DefaultNodes.getNodeFor(info.coin); + .getPrimaryNodeFor(currency: info.coin) ?? + info.coin.defaultNode; unawaited(refresh()); } @@ -310,8 +308,8 @@ mixin NanoInterface<T extends NanoCurrency> on Bip39Wallet<T> { NodeModel getCurrentNode() { return _cachedNode ?? NodeService(secureStorageInterface: secureStorageInterface) - .getPrimaryNodeFor(coin: info.coin) ?? - DefaultNodes.getNodeFor(info.coin); + .getPrimaryNodeFor(currency: info.coin) ?? + info.coin.defaultNode; } @override @@ -407,7 +405,7 @@ mixin NanoInterface<T extends NanoCurrency> on Bip39Wallet<T> { final String link = NanoAccounts.extractPublicKey(linkAsAccount); // construct the send block: - Map<String, String> sendBlock = { + final Map<String, String> sendBlock = { "type": "state", "account": publicAddress, "previous": frontier, @@ -505,14 +503,15 @@ mixin NanoInterface<T extends NanoCurrency> on Bip39Wallet<T> { proxyInfo: prefs.useTor ? TorService.sharedInstance.getProxyInfo() : null, ); final data = await jsonDecode(response.body); - final transactions = - data["history"] is List ? data["history"] as List<dynamic> : []; + final transactions = data["history"] is List + ? data["history"] as List<dynamic> + : <dynamic>[]; if (transactions.isEmpty) { return; } else { - List<Tuple2<Transaction, Address?>> transactionList = []; - for (var tx in transactions) { - var typeString = tx["type"].toString(); + final List<Tuple2<Transaction, Address?>> transactionList = []; + for (final tx in transactions) { + final typeString = tx["type"].toString(); TransactionType transactionType = TransactionType.unknown; if (typeString == "send") { transactionType = TransactionType.outgoing; @@ -524,7 +523,7 @@ mixin NanoInterface<T extends NanoCurrency> on Bip39Wallet<T> { fractionDigits: cryptoCurrency.fractionDigits, ); - var transaction = Transaction( + final transaction = Transaction( walletId: walletId, txid: tx["hash"].toString(), timestamp: int.parse(tx["local_timestamp"].toString()), @@ -544,7 +543,7 @@ mixin NanoInterface<T extends NanoCurrency> on Bip39Wallet<T> { numberOfMessages: null, ); - Address address = transactionType == TransactionType.incoming + final Address address = transactionType == TransactionType.incoming ? receivingAddress : Address( walletId: walletId, @@ -555,7 +554,7 @@ mixin NanoInterface<T extends NanoCurrency> on Bip39Wallet<T> { type: info.coin.primaryAddressType, subType: AddressSubType.nonWallet, ); - Tuple2<Transaction, Address> tuple = Tuple2(transaction, address); + final Tuple2<Transaction, Address> tuple = Tuple2(transaction, address); transactionList.add(tuple); } diff --git a/lib/wallets/wallet/wallet_mixin_interfaces/ordinals_interface.dart b/lib/wallets/wallet/wallet_mixin_interfaces/ordinals_interface.dart index 5b6299f12..09fe10f52 100644 --- a/lib/wallets/wallet/wallet_mixin_interfaces/ordinals_interface.dart +++ b/lib/wallets/wallet/wallet_mixin_interfaces/ordinals_interface.dart @@ -4,9 +4,11 @@ import 'package:stackwallet/models/isar/models/blockchain_data/utxo.dart'; import 'package:stackwallet/models/isar/ordinal.dart'; import 'package:stackwallet/services/litescribe_api.dart'; import 'package:stackwallet/utilities/logger.dart'; +import 'package:stackwallet/wallets/crypto_currency/interfaces/electrumx_currency_interface.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart'; -mixin OrdinalsInterface on ElectrumXInterface { +mixin OrdinalsInterface<T extends ElectrumXCurrencyInterface> + on ElectrumXInterface<T> { final LitescribeAPI _litescribeAPI = LitescribeAPI(baseUrl: 'https://litescribe.io/api'); diff --git a/lib/wallets/wallet/wallet_mixin_interfaces/paynym_interface.dart b/lib/wallets/wallet/wallet_mixin_interfaces/paynym_interface.dart index 202b22943..213c9fd09 100644 --- a/lib/wallets/wallet/wallet_mixin_interfaces/paynym_interface.dart +++ b/lib/wallets/wallet/wallet_mixin_interfaces/paynym_interface.dart @@ -20,11 +20,12 @@ import 'package:stackwallet/models/signing_data.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/bip32_utils.dart'; import 'package:stackwallet/utilities/bip47_utils.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart'; import 'package:stackwallet/utilities/extensions/extensions.dart'; import 'package:stackwallet/utilities/format.dart'; import 'package:stackwallet/utilities/logger.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/dogecoin.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/crypto_currency/interfaces/paynym_currency_interface.dart'; import 'package:stackwallet/wallets/models/tx_data.dart'; import 'package:stackwallet/wallets/wallet/intermediate/bip39_hd_wallet.dart'; @@ -67,7 +68,7 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface> final root = await _getRootNode(); final node = root.derivePath( _basePaynymDerivePath( - testnet: info.coin.isTestNet, + testnet: info.coin.network == CryptoCurrencyNetwork.test, ), ); return node; @@ -158,7 +159,7 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface> final root = await _getRootNode(); final node = root.derivePath( _basePaynymDerivePath( - testnet: info.coin.isTestNet, + testnet: info.coin.network == CryptoCurrencyNetwork.test, ), ); @@ -181,7 +182,7 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface> derivationPath: DerivationPath() ..value = _receivingPaynymAddressDerivationPath( index, - testnet: info.coin.isTestNet, + testnet: info.coin.network == CryptoCurrencyNetwork.test, ), type: generateSegwitAddress ? AddressType.p2wpkh : AddressType.p2pkh, subType: AddressSubType.paynymReceive, @@ -218,7 +219,7 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface> derivationPath: DerivationPath() ..value = _sendPaynymAddressDerivationPath( index, - testnet: info.coin.isTestNet, + testnet: info.coin.network == CryptoCurrencyNetwork.test, ), type: AddressType.nonWallet, subType: AddressSubType.paynymSend, @@ -275,14 +276,18 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface> final codes = await getAllPaymentCodesFromNotificationTransactions(); final List<Future<void>> futures = []; for (final code in codes) { - futures.add(checkCurrentPaynymReceivingAddressForTransactions( - sender: code, - isSegwit: true, - )); - futures.add(checkCurrentPaynymReceivingAddressForTransactions( - sender: code, - isSegwit: false, - )); + futures.add( + checkCurrentPaynymReceivingAddressForTransactions( + sender: code, + isSegwit: true, + ), + ); + futures.add( + checkCurrentPaynymReceivingAddressForTransactions( + sender: code, + isSegwit: false, + ), + ); } await Future.wait(futures); } @@ -309,7 +314,7 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface> final node = root .derivePath( _basePaynymDerivePath( - testnet: info.coin.isTestNet, + testnet: info.coin.network == CryptoCurrencyNetwork.test, ), ) .derive(0); @@ -323,7 +328,11 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface> final node = await _getRootNode(); final paymentCode = PaymentCode.fromBip32Node( - node.derivePath(_basePaynymDerivePath(testnet: info.coin.isTestNet)), + node.derivePath( + _basePaynymDerivePath( + testnet: info.coin.network == CryptoCurrencyNetwork.test, + ), + ), networkType: networkType, shouldSetSegwitBit: isSegwit, ); @@ -333,8 +342,10 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface> Future<Uint8List> signWithNotificationKey(Uint8List data) async { final myPrivateKeyNode = await deriveNotificationBip32Node(); - final pair = btc_dart.ECPair.fromPrivateKey(myPrivateKeyNode.privateKey!, - network: networkType); + final pair = btc_dart.ECPair.fromPrivateKey( + myPrivateKeyNode.privateKey!, + network: networkType, + ); final signed = pair.sign(SHA256Digest().process(data)); return signed; } @@ -363,7 +374,8 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface> if (!(await hasConnected(txData.paynymAccountLite!.code.toString()))) { throw PaynymSendException( - "No notification transaction sent to $paymentCode,"); + "No notification transaction sent to $paymentCode,", + ); } else { final myPrivateKeyNode = await deriveNotificationBip32Node(); final sendToAddress = await nextUnusedSendAddressFrom( @@ -465,7 +477,9 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface> for (var i = 0; i < availableOutputs.length; i++) { if (availableOutputs[i].isBlocked == false && availableOutputs[i].isConfirmed( - await fetchChainHeight(), cryptoCurrency.minConfirms) == + await fetchChainHeight(), + cryptoCurrency.minConfirms, + ) == true) { spendableOutputs.add(availableOutputs[i]); spendableSatoshiValue += BigInt.from(availableOutputs[i].value); @@ -475,11 +489,13 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface> if (spendableSatoshiValue < amountToSend.raw) { // insufficient balance throw InsufficientBalanceException( - "Spendable balance is less than the minimum required for a notification transaction."); + "Spendable balance is less than the minimum required for a notification transaction.", + ); } else if (spendableSatoshiValue == amountToSend.raw) { // insufficient balance due to missing amount to cover fee throw InsufficientBalanceException( - "Remaining balance does not cover the network fee."); + "Remaining balance does not cover the network fee.", + ); } // sort spendable by age (oldest first) @@ -487,7 +503,7 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface> BigInt satoshisBeingUsed = BigInt.zero; int outputsBeingUsed = 0; - List<UTXO> utxoObjectsToUse = []; + final List<UTXO> utxoObjectsToUse = []; for (int i = 0; satoshisBeingUsed < amountToSend.raw && i < spendableOutputs.length; @@ -546,7 +562,7 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface> ), ); - if (info.coin == Coin.dogecoin || info.coin == Coin.dogecoinTestNet) { + if (info.coin is Dogecoin) { if (feeForNoChange < vSizeForNoChange * BigInt.from(1000)) { feeForNoChange = vSizeForNoChange * BigInt.from(1000); } @@ -587,21 +603,22 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface> } final txData = TxData( - raw: txn.item1, - recipients: [ - ( - address: targetPaymentCodeString, - amount: amountToSend, - isChange: false, - ), - ], - fee: Amount( - rawValue: feeBeingPaid, - fractionDigits: cryptoCurrency.fractionDigits, + raw: txn.item1, + recipients: [ + ( + address: targetPaymentCodeString, + amount: amountToSend, + isChange: false, ), - vSize: txn.item2, - utxos: utxoSigningData.map((e) => e.utxo).toSet(), - note: "PayNym connect"); + ], + fee: Amount( + rawValue: feeBeingPaid, + fractionDigits: cryptoCurrency.fractionDigits, + ), + vSize: txn.item2, + utxos: utxoSigningData.map((e) => e.utxo).toSet(), + note: "PayNym connect", + ); return txData; } else { @@ -613,24 +630,25 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface> change: BigInt.zero, ); - BigInt feeBeingPaid = satoshisBeingUsed - amountToSend.raw; + final BigInt feeBeingPaid = satoshisBeingUsed - amountToSend.raw; final txData = TxData( - raw: txn.item1, - recipients: [ - ( - address: targetPaymentCodeString, - amount: amountToSend, - isChange: false, - ) - ], - fee: Amount( - rawValue: feeBeingPaid, - fractionDigits: cryptoCurrency.fractionDigits, + raw: txn.item1, + recipients: [ + ( + address: targetPaymentCodeString, + amount: amountToSend, + isChange: false, ), - vSize: txn.item2, - utxos: utxoSigningData.map((e) => e.utxo).toSet(), - note: "PayNym connect"); + ], + fee: Amount( + rawValue: feeBeingPaid, + fractionDigits: cryptoCurrency.fractionDigits, + ), + vSize: txn.item2, + utxos: utxoSigningData.map((e) => e.utxo).toSet(), + note: "PayNym connect", + ); return txData; } @@ -643,24 +661,25 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface> change: BigInt.zero, ); - BigInt feeBeingPaid = satoshisBeingUsed - amountToSend.raw; + final BigInt feeBeingPaid = satoshisBeingUsed - amountToSend.raw; final txData = TxData( - raw: txn.item1, - recipients: [ - ( - address: targetPaymentCodeString, - amount: amountToSend, - isChange: false, - ) - ], - fee: Amount( - rawValue: feeBeingPaid, - fractionDigits: cryptoCurrency.fractionDigits, + raw: txn.item1, + recipients: [ + ( + address: targetPaymentCodeString, + amount: amountToSend, + isChange: false, ), - vSize: txn.item2, - utxos: utxoSigningData.map((e) => e.utxo).toSet(), - note: "PayNym connect"); + ], + fee: Amount( + rawValue: feeBeingPaid, + fractionDigits: cryptoCurrency.fractionDigits, + ), + vSize: txn.item2, + utxos: utxoSigningData.map((e) => e.utxo).toSet(), + note: "PayNym connect", + ); return txData; } else { @@ -674,7 +693,8 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface> ); } else { throw InsufficientBalanceException( - "Remaining balance does not cover the network fee."); + "Remaining balance does not cover the network fee.", + ); } } } catch (e) { @@ -900,8 +920,10 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface> txHash: txHash, ); } catch (e, s) { - Logging.instance.log("Exception rethrown from confirmSend(): $e\n$s", - level: LogLevel.Error); + Logging.instance.log( + "Exception rethrown from confirmSend(): $e\n$s", + level: LogLevel.Error, + ); rethrow; } } @@ -1143,7 +1165,7 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface> .subTypeEqualTo(TransactionSubType.bip47Notification) .findAll(); - List<PaymentCode> codes = []; + final List<PaymentCode> codes = []; for (final tx in txns) { // tx is sent so we can check the address's otherData for the code String @@ -1201,7 +1223,8 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface> } Future<void> checkForNotificationTransactionsTo( - Set<String> otherCodeStrings) async { + Set<String> otherCodeStrings, + ) async { final sentNotificationTransactions = await mainDB.isar.transactionV2s .where() .walletIdEqualTo(walletId) @@ -1214,7 +1237,8 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface> final List<PaymentCode> codes = []; for (final codeString in otherCodeStrings) { codes.add( - PaymentCode.fromPaymentCode(codeString, networkType: networkType)); + PaymentCode.fromPaymentCode(codeString, networkType: networkType), + ); } for (final tx in sentNotificationTransactions) { @@ -1303,7 +1327,7 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface> final mySendBip32Node = await deriveNotificationBip32Node(); - List<Address> addresses = []; + final List<Address> addresses = []; int receivingGapCounter = 0; int outgoingGapCounter = 0; @@ -1445,7 +1469,7 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface> final root = await _getRootNode(); final node = root.derivePath( _basePaynymDerivePath( - testnet: info.coin.isTestNet, + testnet: info.coin.network == CryptoCurrencyNetwork.test, ), ); final paymentCode = PaymentCode.fromBip32Node( @@ -1473,7 +1497,7 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface> derivationIndex: 0, derivationPath: DerivationPath() ..value = _notificationDerivationPath( - testnet: info.coin.isTestNet, + testnet: info.coin.network == CryptoCurrencyNetwork.test, ), type: AddressType.p2pkh, subType: AddressSubType.paynymNotification, @@ -1559,7 +1583,8 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface> Uint8List _randomBytes(int n) { final Random rng = Random.secure(); return Uint8List.fromList( - List<int>.generate(n, (_) => rng.nextInt(0xFF + 1))); + List<int>.generate(n, (_) => rng.nextInt(0xFF + 1)), + ); } // ================== Overrides ============================================== @@ -1567,18 +1592,20 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface> @override Future<void> updateTransactions({List<Address>? overrideAddresses}) async { // Get all addresses. - List<Address> allAddressesOld = + final List<Address> allAddressesOld = overrideAddresses ?? await fetchAddressesForElectrumXScan(); // Separate receiving and change addresses. - Set<String> receivingAddresses = allAddressesOld - .where((e) => - e.subType == AddressSubType.receiving || - e.subType == AddressSubType.paynymNotification || - e.subType == AddressSubType.paynymReceive) + final Set<String> receivingAddresses = allAddressesOld + .where( + (e) => + e.subType == AddressSubType.receiving || + e.subType == AddressSubType.paynymNotification || + e.subType == AddressSubType.paynymReceive, + ) .map((e) => e.value) .toSet(); - Set<String> changeAddresses = allAddressesOld + final Set<String> changeAddresses = allAddressesOld .where((e) => e.subType == AddressSubType.change) .map((e) => e.value) .toSet(); @@ -1591,7 +1618,7 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface> await fetchHistory(allAddressesSet); // Only parse new txs (not in db yet). - List<Map<String, dynamic>> allTransactions = []; + final List<Map<String, dynamic>> allTransactions = []; for (final txHash in allTxHashes) { // Check for duplicates by searching for tx by tx_hash in db. // final storedTx = await mainDB.isar.transactionV2s @@ -1606,7 +1633,7 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface> final tx = await electrumXCachedClient.getTransaction( txHash: txHash["tx_hash"] as String, verbose: true, - coin: cryptoCurrency.coin, + cryptoCurrency: cryptoCurrency, ); // Only tx to list once. @@ -1648,12 +1675,12 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface> final inputTx = await electrumXCachedClient.getTransaction( txHash: txid, - coin: cryptoCurrency.coin, + cryptoCurrency: cryptoCurrency, ); final prevOutJson = Map<String, dynamic>.from( - (inputTx["vout"] as List).firstWhere((e) => e["n"] == vout) - as Map); + (inputTx["vout"] as List).firstWhere((e) => e["n"] == vout) as Map, + ); final prevOut = OutputV2.fromElectrumXJson( prevOutJson, @@ -1726,7 +1753,8 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface> TransactionSubType subType = TransactionSubType.none; if (outputs.length > 1 && inputs.isNotEmpty) { for (int i = 0; i < outputs.length; i++) { - List<String>? scriptChunks = outputs[i].scriptPubKeyAsm?.split(" "); + final List<String>? scriptChunks = + outputs[i].scriptPubKeyAsm?.split(" "); if (scriptChunks?.length == 2 && scriptChunks?[0] == "OP_RETURN") { final blindedPaymentCode = scriptChunks![1]; final bytes = blindedPaymentCode.toUint8ListFromHex; @@ -1809,7 +1837,7 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface> final outputs = jsonTX["vout"] as List; for (int i = 0; i < outputs.length; i++) { final output = outputs[i]; - List<String>? scriptChunks = + final List<String>? scriptChunks = (output['scriptPubKey']?['asm'] as String?)?.split(" "); if (scriptChunks?.length == 2 && scriptChunks?[0] == "OP_RETURN") { final blindedPaymentCode = scriptChunks![1]; diff --git a/lib/wallets/wallet/wallet_mixin_interfaces/spark_interface.dart b/lib/wallets/wallet/wallet_mixin_interfaces/spark_interface.dart index 7aaa1d3ed..ece37026e 100644 --- a/lib/wallets/wallet/wallet_mixin_interfaces/spark_interface.dart +++ b/lib/wallets/wallet/wallet_mixin_interfaces/spark_interface.dart @@ -17,6 +17,7 @@ import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart'; import 'package:stackwallet/utilities/extensions/extensions.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; +import 'package:stackwallet/wallets/crypto_currency/interfaces/electrumx_currency_interface.dart'; import 'package:stackwallet/wallets/isar/models/spark_coin.dart'; import 'package:stackwallet/wallets/models/tx_data.dart'; import 'package:stackwallet/wallets/wallet/intermediate/bip39_hd_wallet.dart'; @@ -34,7 +35,8 @@ const OP_SPARKMINT = 0xd1; const OP_SPARKSMINT = 0xd2; const OP_SPARKSPEND = 0xd3; -mixin SparkInterface on Bip39HDWallet, ElectrumXInterface { +mixin SparkInterface<T extends ElectrumXCurrencyInterface> + on Bip39HDWallet<T>, ElectrumXInterface<T> { String? _sparkChangeAddressCached; /// Spark change address. Should generally not be exposed to end users. @@ -258,7 +260,7 @@ mixin SparkInterface on Bip39HDWallet, ElectrumXInterface { for (int i = 1; i <= currentId; i++) { final set = await electrumXCachedClient.getSparkAnonymitySet( groupId: i.toString(), - coin: info.coin, + cryptoCurrency: info.coin, useOnlyCacheIfNotEmpty: true, ); set["coinGroupID"] = i; @@ -619,12 +621,12 @@ mixin SparkInterface on Bip39HDWallet, ElectrumXInterface { final anonymitySetFuture = electrumXCachedClient.getSparkAnonymitySet( groupId: latestSparkCoinId.toString(), - coin: info.coin, + cryptoCurrency: info.coin, useOnlyCacheIfNotEmpty: false, ); - final spentCoinTagsFuture = - electrumXCachedClient.getSparkUsedCoinsTags(coin: info.coin); + final spentCoinTagsFuture = electrumXCachedClient.getSparkUsedCoinsTags( + cryptoCurrency: info.coin); final futureResults = await Future.wait([ anonymitySetFuture, @@ -1600,7 +1602,7 @@ mixin SparkInterface on Bip39HDWallet, ElectrumXInterface { for (final coin in coinsToCheck) { final tx = await electrumXCachedClient.getTransaction( txHash: coin.txHash, - coin: info.coin, + cryptoCurrency: info.coin, ); if (tx["height"] is int) { updatedCoins.add(coin.copyWith(height: tx["height"] as int)); diff --git a/lib/widgets/address_book_card.dart b/lib/widgets/address_book_card.dart index f40f4f432..8a795437f 100644 --- a/lib/widgets/address_book_card.dart +++ b/lib/widgets/address_book_card.dart @@ -16,13 +16,14 @@ import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/models/isar/models/contact_entry.dart'; import 'package:stackwallet/pages/address_book_views/subviews/contact_popup.dart'; import 'package:stackwallet/providers/global/address_book_service_provider.dart'; +import 'package:stackwallet/supported_coins.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/themes/theme_providers.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/conditional_parent.dart'; import 'package:stackwallet/widgets/expandable.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; @@ -69,9 +70,9 @@ class _AddressBookCardState extends ConsumerState<AddressBookCard> { final contact = _contact!; - final List<Coin> coins = []; + final List<CryptoCurrency> coins = []; - for (final coin in Coin.values) { + for (final coin in SupportedCoins.cryptocurrencies) { if (contact.addresses.where((e) => e.coin == coin).isNotEmpty) { coins.add(coin); } diff --git a/lib/widgets/choose_coin_view.dart b/lib/widgets/choose_coin_view.dart index 52ff990f2..862585786 100644 --- a/lib/widgets/choose_coin_view.dart +++ b/lib/widgets/choose_coin_view.dart @@ -14,11 +14,13 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/providers/providers.dart'; +import 'package:stackwallet/supported_coins.dart'; import 'package:stackwallet/themes/coin_icon_provider.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/background.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; @@ -33,11 +35,11 @@ import 'package:stackwallet/widgets/rounded_white_container.dart'; class ChooseCoinView extends ConsumerStatefulWidget { const ChooseCoinView({ - Key? key, + super.key, required this.title, required this.coinAdditional, required this.nextRouteName, - }) : super(key: key); + }); static const String routeName = "/chooseCoin"; @@ -50,12 +52,14 @@ class ChooseCoinView extends ConsumerStatefulWidget { } class _ChooseCoinViewState extends ConsumerState<ChooseCoinView> { - List<Coin> _coins = [...Coin.values]; + List<CryptoCurrency> _coins = [...SupportedCoins.cryptocurrencies]; @override void initState() { _coins = _coins.toList(); - _coins.remove(Coin.firoTestNet); + _coins.removeWhere( + (e) => e.identifier == Firo(CryptoCurrencyNetwork.test).identifier, + ); super.initState(); } @@ -66,12 +70,17 @@ class _ChooseCoinViewState extends ConsumerState<ChooseCoinView> { @override Widget build(BuildContext context) { - bool showTestNet = ref.watch( + final bool showTestNet = ref.watch( prefsChangeNotifierProvider.select((value) => value.showTestNetCoins), ); - List<Coin> coins = - showTestNet ? _coins : _coins.where((e) => !e.isTestNet).toList(); + final List<CryptoCurrency> coins = showTestNet + ? _coins + : _coins + .where( + (e) => e.network == CryptoCurrencyNetwork.main, + ) + .toList(); return Background( child: Scaffold( diff --git a/lib/widgets/crypto_notifications.dart b/lib/widgets/crypto_notifications.dart index b570ae4f9..52c5b3fc5 100644 --- a/lib/widgets/crypto_notifications.dart +++ b/lib/widgets/crypto_notifications.dart @@ -16,7 +16,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/services/notifications_api.dart'; import 'package:stackwallet/themes/coin_icon_provider.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; abstract class CryptoNotificationsEventBus { static final instance = EventBus(); @@ -28,7 +28,7 @@ class CryptoNotificationEvent { final String walletName; final DateTime date; final bool shouldWatchForUpdates; - final Coin coin; + final CryptoCurrency coin; final String? txid; final int? confirmations; final int? requiredConfirmations; @@ -52,9 +52,9 @@ class CryptoNotificationEvent { class CryptoNotifications extends ConsumerStatefulWidget { const CryptoNotifications({ - Key? key, + super.key, required this.child, - }) : super(key: key); + }); final Widget child; @@ -74,7 +74,7 @@ class _CryptoNotificationsState extends ConsumerState<CryptoNotifications> { iconAssetName: ref.read(coinIconProvider(event.coin)), date: event.date, shouldWatchForUpdates: event.shouldWatchForUpdates, - coinName: event.coin.name, + coinName: event.coin.identifier, txid: event.txid, confirmations: event.confirmations, requiredConfirmations: event.requiredConfirmations, diff --git a/lib/widgets/desktop/desktop_fee_dialog.dart b/lib/widgets/desktop/desktop_fee_dialog.dart index a4a5a9abc..237c2bf8d 100644 --- a/lib/widgets/desktop/desktop_fee_dialog.dart +++ b/lib/widgets/desktop/desktop_fee_dialog.dart @@ -9,10 +9,13 @@ import 'package:stackwallet/providers/wallet/public_private_balance_state_provid import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount_formatter.dart'; -import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/ethereum.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/monero.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/wownero.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/isar/providers/eth/current_token_wallet_provider.dart'; import 'package:stackwallet/wallets/wallet/impl/firo_wallet.dart'; import 'package:stackwallet/widgets/animated_text.dart'; @@ -22,10 +25,10 @@ import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart'; class DesktopFeeDialog extends ConsumerStatefulWidget { const DesktopFeeDialog({ - Key? key, + super.key, required this.walletId, this.isToken = false, - }) : super(key: key); + }); final String walletId; final bool isToken; @@ -44,24 +47,28 @@ class _DesktopFeeDialogState extends ConsumerState<DesktopFeeDialog> { required Amount amount, required FeeRateType feeRateType, required int feeRate, - required Coin coin, + required CryptoCurrency coin, }) async { switch (feeRateType) { case FeeRateType.fast: if (ref - .read(widget.isToken - ? tokenFeeSessionCacheProvider - : feeSheetSessionCacheProvider) + .read( + widget.isToken + ? tokenFeeSessionCacheProvider + : feeSheetSessionCacheProvider, + ) .fast[amount] == null) { if (widget.isToken == false) { final wallet = ref.read(pWallets).getWallet(walletId); - if (coin == Coin.monero || coin == Coin.wownero) { + if (coin is Monero || coin is Wownero) { final fee = await wallet.estimateFeeFor( - amount, MoneroTransactionPriority.fast.raw!); + amount, + MoneroTransactionPriority.fast.raw!, + ); ref.read(feeSheetSessionCacheProvider).fast[amount] = fee; - } else if (coin == Coin.firo || coin == Coin.firoTestNet) { + } else if (coin is Firo) { final Amount fee; switch (ref.read(publicPrivateBalanceStateProvider.state).state) { case FiroType.spark: @@ -86,26 +93,32 @@ class _DesktopFeeDialogState extends ConsumerState<DesktopFeeDialog> { } } return ref - .read(widget.isToken - ? tokenFeeSessionCacheProvider - : feeSheetSessionCacheProvider) + .read( + widget.isToken + ? tokenFeeSessionCacheProvider + : feeSheetSessionCacheProvider, + ) .fast[amount]!; case FeeRateType.average: if (ref - .read(widget.isToken - ? tokenFeeSessionCacheProvider - : feeSheetSessionCacheProvider) + .read( + widget.isToken + ? tokenFeeSessionCacheProvider + : feeSheetSessionCacheProvider, + ) .average[amount] == null) { if (widget.isToken == false) { final wallet = ref.read(pWallets).getWallet(walletId); - if (coin == Coin.monero || coin == Coin.wownero) { + if (coin is Monero || coin is Wownero) { final fee = await wallet.estimateFeeFor( - amount, MoneroTransactionPriority.regular.raw!); + amount, + MoneroTransactionPriority.regular.raw!, + ); ref.read(feeSheetSessionCacheProvider).average[amount] = fee; - } else if (coin == Coin.firo || coin == Coin.firoTestNet) { + } else if (coin is Firo) { final Amount fee; switch (ref.read(publicPrivateBalanceStateProvider.state).state) { case FiroType.spark: @@ -130,26 +143,32 @@ class _DesktopFeeDialogState extends ConsumerState<DesktopFeeDialog> { } } return ref - .read(widget.isToken - ? tokenFeeSessionCacheProvider - : feeSheetSessionCacheProvider) + .read( + widget.isToken + ? tokenFeeSessionCacheProvider + : feeSheetSessionCacheProvider, + ) .average[amount]!; case FeeRateType.slow: if (ref - .read(widget.isToken - ? tokenFeeSessionCacheProvider - : feeSheetSessionCacheProvider) + .read( + widget.isToken + ? tokenFeeSessionCacheProvider + : feeSheetSessionCacheProvider, + ) .slow[amount] == null) { if (widget.isToken == false) { final wallet = ref.read(pWallets).getWallet(walletId); - if (coin == Coin.monero || coin == Coin.wownero) { + if (coin is Monero || coin is Wownero) { final fee = await wallet.estimateFeeFor( - amount, MoneroTransactionPriority.slow.raw!); + amount, + MoneroTransactionPriority.slow.raw!, + ); ref.read(feeSheetSessionCacheProvider).slow[amount] = fee; - } else if (coin == Coin.firo || coin == Coin.firoTestNet) { + } else if (coin is Firo) { final Amount fee; switch (ref.read(publicPrivateBalanceStateProvider.state).state) { case FiroType.spark: @@ -174,9 +193,11 @@ class _DesktopFeeDialogState extends ConsumerState<DesktopFeeDialog> { } } return ref - .read(widget.isToken - ? tokenFeeSessionCacheProvider - : feeSheetSessionCacheProvider) + .read( + widget.isToken + ? tokenFeeSessionCacheProvider + : feeSheetSessionCacheProvider, + ) .slow[amount]!; default: return Amount.zero; @@ -250,14 +271,14 @@ class _DesktopFeeDialogState extends ConsumerState<DesktopFeeDialog> { class DesktopFeeItem extends ConsumerStatefulWidget { const DesktopFeeItem({ - Key? key, + super.key, required this.feeObject, required this.feeRateType, required this.walletId, required this.feeFor, required this.isSelected, this.isButton = true, - }) : super(key: key); + }); final FeeObject? feeObject; final FeeRateType feeRateType; @@ -266,7 +287,7 @@ class DesktopFeeItem extends ConsumerStatefulWidget { required Amount amount, required FeeRateType feeRateType, required int feeRate, - required Coin coin, + required CryptoCurrency coin, }) feeFor; final bool isSelected; final bool isButton; @@ -287,7 +308,9 @@ class _DesktopFeeItemState extends ConsumerState<DesktopFeeItem> { ]; String estimatedTimeToBeIncludedInNextBlock( - int targetBlockTime, int estimatedNumberOfBlocks) { + int targetBlockTime, + int estimatedNumberOfBlocks, + ) { int time = targetBlockTime * estimatedNumberOfBlocks; int hours = (time / 3600).floor(); @@ -338,14 +361,14 @@ class _DesktopFeeItemState extends ConsumerState<DesktopFeeItem> { (value) => value.getWallet(widget.walletId).info.coin, ), ); - if ((coin == Coin.firo || coin == Coin.firoTestNet) && + if ((coin is Firo) && ref.watch(publicPrivateBalanceStateProvider.state).state == "Private") { return Text( "~${ref.watch(pAmountFormatter(coin)).format( Amount( rawValue: BigInt.parse("3794"), - fractionDigits: coin.decimals, + fractionDigits: coin.fractionDigits, ), indicatePrecisionLoss: false, )}", @@ -378,7 +401,8 @@ class _DesktopFeeItemState extends ConsumerState<DesktopFeeItem> { } final wallet = ref.watch( - pWallets.select((value) => value.getWallet(widget.walletId))); + pWallets.select((value) => value.getWallet(widget.walletId)), + ); if (widget.feeObject == null) { return AnimatedText( @@ -410,10 +434,10 @@ class _DesktopFeeItemState extends ConsumerState<DesktopFeeItem> { indicatePrecisionLoss: false, )})"; - timeString = wallet.info.coin == Coin.ethereum + timeString = wallet.info.coin is Ethereum ? "" : estimatedTimeToBeIncludedInNextBlock( - Constants.targetBlockTimeInSeconds(wallet.info.coin), + wallet.info.coin.targetBlockTimeSeconds, widget.feeRateType == FeeRateType.fast ? widget.feeObject!.numberOfBlocksFast : widget.feeRateType == FeeRateType.slow diff --git a/lib/widgets/dialogs/tor_warning_dialog.dart b/lib/widgets/dialogs/tor_warning_dialog.dart index d4bd7dc81..7f4bd7cae 100644 --- a/lib/widgets/dialogs/tor_warning_dialog.dart +++ b/lib/widgets/dialogs/tor_warning_dialog.dart @@ -1,20 +1,20 @@ import 'package:flutter/cupertino.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/desktop/primary_button.dart'; import 'package:stackwallet/widgets/desktop/secondary_button.dart'; import 'package:stackwallet/widgets/dialogs/basic_dialog.dart'; class TorWarningDialog extends StatelessWidget { - final Coin coin; + final CryptoCurrency coin; final VoidCallback? onContinue; final VoidCallback? onCancel; - TorWarningDialog({ - Key? key, + const TorWarningDialog({ + super.key, required this.coin, this.onContinue, this.onCancel, - }) : super(key: key); + }); @override Widget build(BuildContext context) { diff --git a/lib/widgets/fee_slider.dart b/lib/widgets/fee_slider.dart index 64e3af12b..b2cdc87e6 100644 --- a/lib/widgets/fee_slider.dart +++ b/lib/widgets/fee_slider.dart @@ -1,8 +1,9 @@ import 'dart:math'; import 'package:flutter/material.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/dogecoin.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; class FeeSlider extends StatefulWidget { const FeeSlider({ @@ -12,7 +13,7 @@ class FeeSlider extends StatefulWidget { this.showWU = false, }); - final Coin coin; + final CryptoCurrency coin; final bool showWU; final void Function(int) onSatVByteChanged; @@ -51,12 +52,10 @@ class _FeeSliderState extends State<FeeSlider> { setState(() { sliderValue = value; final number = pow(sliderValue * (max - min) + min, 4).toDouble(); - switch (widget.coin) { - case Coin.dogecoin: - case Coin.dogecoinTestNet: - rate = (number * 1000).toInt(); - default: - rate = number.toInt(); + if (widget.coin is Dogecoin) { + rate = (number * 1000).toInt(); + } else { + rate = number.toInt(); } }); widget.onSatVByteChanged(rate); diff --git a/lib/widgets/icon_widgets/eth_token_icon.dart b/lib/widgets/icon_widgets/eth_token_icon.dart index dbc2d6794..0cd730690 100644 --- a/lib/widgets/icon_widgets/eth_token_icon.dart +++ b/lib/widgets/icon_widgets/eth_token_icon.dart @@ -15,14 +15,15 @@ import 'package:isar/isar.dart'; import 'package:stackwallet/models/isar/exchange_cache/currency.dart'; import 'package:stackwallet/services/exchange/exchange_data_loading_service.dart'; import 'package:stackwallet/themes/coin_icon_provider.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/ethereum.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; class EthTokenIcon extends ConsumerStatefulWidget { const EthTokenIcon({ - Key? key, + super.key, required this.contractAddress, this.size = 22, - }) : super(key: key); + }); final String contractAddress; final double size; @@ -49,7 +50,7 @@ class _EthTokenIconState extends ConsumerState<EthTokenIcon> { Widget build(BuildContext context) { if (imageUrl == null || imageUrl!.isEmpty) { return SvgPicture.asset( - ref.watch(coinIconProvider(Coin.ethereum)), + ref.watch(coinIconProvider(Ethereum(CryptoCurrencyNetwork.main))), width: widget.size, height: widget.size, ); diff --git a/lib/widgets/managed_favorite.dart b/lib/widgets/managed_favorite.dart index b5266ea2a..5ab0800d5 100644 --- a/lib/widgets/managed_favorite.dart +++ b/lib/widgets/managed_favorite.dart @@ -16,21 +16,22 @@ import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/providers/db/main_db_provider.dart'; import 'package:stackwallet/themes/coin_icon_provider.dart'; import 'package:stackwallet/themes/stack_colors.dart'; +import 'package:stackwallet/themes/theme_providers.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount_formatter.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; import 'package:stackwallet/widgets/custom_buttons/favorite_toggle.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; class ManagedFavorite extends ConsumerStatefulWidget { const ManagedFavorite({ - Key? key, + super.key, required this.walletId, - }) : super(key: key); + }); final String walletId; @@ -50,7 +51,7 @@ class _ManagedFavoriteCardState extends ConsumerState<ManagedFavorite> { final coin = ref.watch(pWalletCoin(walletId)); Amount total = ref.watch(pWalletBalance(walletId)).total; - if (coin == Coin.firo || coin == Coin.firoTestNet) { + if (coin is Firo) { final balancePrivate = ref.watch(pWalletBalanceSecondary(walletId)).total + ref.watch(pWalletBalanceTertiary(walletId)).total; @@ -85,10 +86,7 @@ class _ManagedFavoriteCardState extends ConsumerState<ManagedFavorite> { children: [ Container( decoration: BoxDecoration( - color: Theme.of(context) - .extension<StackColors>()! - .colorForCoin(coin) - .withOpacity(0.5), + color: ref.watch(pCoinColor(coin)).withOpacity(0.5), borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, ), @@ -141,7 +139,7 @@ class _ManagedFavoriteCardState extends ConsumerState<ManagedFavorite> { .extension<StackColors>()! .buttonTextBorderless, ), - ) + ), ], ), ), diff --git a/lib/widgets/node_card.dart b/lib/widgets/node_card.dart index a6ac18302..65bf02fb4 100644 --- a/lib/widgets/node_card.dart +++ b/lib/widgets/node_card.dart @@ -13,29 +13,21 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; -import 'package:solana/solana.dart'; -import 'package:stackwallet/models/node_model.dart'; import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart'; import 'package:stackwallet/providers/global/active_wallet_provider.dart'; +import 'package:stackwallet/providers/global/secure_store_provider.dart'; import 'package:stackwallet/providers/providers.dart'; -import 'package:stackwallet/services/tor_service.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/connection_check/electrum_connection_check.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/default_nodes.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/sync_type_enum.dart'; -import 'package:stackwallet/utilities/logger.dart'; -import 'package:stackwallet/utilities/test_epic_box_connection.dart'; -import 'package:stackwallet/utilities/test_eth_node_connection.dart'; -import 'package:stackwallet/utilities/test_monero_node_connection.dart'; -import 'package:stackwallet/utilities/test_stellar_node_connection.dart'; +import 'package:stackwallet/utilities/test_node_connection.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; -import 'package:stackwallet/wallets/api/tezos/tezos_rpc_api.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/conditional_parent.dart'; import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart'; import 'package:stackwallet/widgets/expandable.dart'; @@ -45,13 +37,13 @@ import 'package:tuple/tuple.dart'; class NodeCard extends ConsumerStatefulWidget { const NodeCard({ - Key? key, + super.key, required this.nodeId, required this.coin, required this.popBackToRoute, - }) : super(key: key); + }); - final Coin coin; + final CryptoCurrency coin; final String nodeId; final String popBackToRoute; @@ -97,161 +89,6 @@ class _NodeCardState extends ConsumerState<NodeCard> { } } - Future<bool> _testConnection( - NodeModel node, - BuildContext context, - WidgetRef ref, - ) async { - bool testPassed = false; - - switch (widget.coin) { - case Coin.epicCash: - try { - testPassed = await testEpicNodeConnection( - NodeFormData() - ..host = node.host - ..useSSL = node.useSSL - ..port = node.port, - ) != - null; - } catch (e, s) { - Logging.instance.log("$e\n$s", level: LogLevel.Warning); - } - break; - - case Coin.monero: - case Coin.wownero: - try { - final uri = Uri.parse(node.host); - if (uri.scheme.startsWith("http")) { - final String path = uri.path.isEmpty ? "/json_rpc" : uri.path; - - String uriString = "${uri.scheme}://${uri.host}:${node.port}$path"; - - final response = await testMoneroNodeConnection( - Uri.parse(uriString), - false, - ); - - if (response.cert != null) { - if (mounted) { - final shouldAllowBadCert = await showBadX509CertificateDialog( - response.cert!, - response.url!, - response.port!, - context, - ); - - if (shouldAllowBadCert) { - final response = await testMoneroNodeConnection( - Uri.parse(uriString), true); - testPassed = response.success; - } - } - } else { - testPassed = response.success; - } - } - } catch (e, s) { - Logging.instance.log("$e\n$s", level: LogLevel.Warning); - } - - break; - - case Coin.bitcoin: - case Coin.litecoin: - case Coin.dogecoin: - case Coin.firo: - case Coin.particl: - case Coin.bitcoinTestNet: - case Coin.firoTestNet: - case Coin.dogecoinTestNet: - case Coin.bitcoincash: - case Coin.litecoinTestNet: - case Coin.namecoin: - case Coin.bitcoincashTestnet: - case Coin.eCash: - case Coin.bitcoinFrost: - case Coin.bitcoinFrostTestNet: - case Coin.peercoin: - case Coin.peercoinTestNet: - try { - testPassed = await checkElectrumServer( - host: node.host, - port: node.port, - useSSL: node.useSSL, - overridePrefs: ref.read(prefsChangeNotifierProvider), - overrideTorService: ref.read(pTorService), - ); - } catch (_) { - testPassed = false; - } - - break; - - case Coin.ethereum: - try { - testPassed = await testEthNodeConnection(node.host); - } catch (_) { - testPassed = false; - } - break; - - case Coin.nano: - case Coin.banano: - throw UnimplementedError(); - //TODO: check network/node - case Coin.tezos: - try { - testPassed = await TezosRpcAPI.testNetworkConnection( - nodeInfo: (host: node.host, port: node.port), - ); - } catch (_) {} - break; - case Coin.stellar: - case Coin.stellarTestnet: - try { - testPassed = await testStellarNodeConnection(node.host, node.port); - } catch (_) { - testPassed = false; - } - break; - - case Coin.solana: - try { - RpcClient rpcClient; - if (node.host.startsWith("http") || node.host.startsWith("https")) { - rpcClient = RpcClient("${node.host}:${node.port}"); - } else { - rpcClient = RpcClient("http://${node.host}:${node.port}"); - } - await rpcClient.getEpochInfo().then((value) => testPassed = true); - } catch (_) { - testPassed = false; - } - break; - } - - if (testPassed) { - // showFloatingFlushBar( - // type: FlushBarType.success, - // message: "Server ping success", - // context: context, - // ); - } else { - unawaited( - showFloatingFlushBar( - type: FlushBarType.warning, - iconAsset: Assets.svg.circleAlert, - message: "Could not connect to node", - context: context, - ), - ); - } - - return testPassed; - } - @override void initState() { nodeId = widget.nodeId; @@ -260,10 +97,14 @@ class _NodeCardState extends ConsumerState<NodeCard> { @override Widget build(BuildContext context) { - final node = ref.watch(nodeServiceChangeNotifierProvider - .select((value) => value.getPrimaryNodeFor(coin: widget.coin))); - final _node = ref.watch(nodeServiceChangeNotifierProvider - .select((value) => value.getNodeById(id: nodeId)))!; + final node = ref.watch( + nodeServiceChangeNotifierProvider + .select((value) => value.getPrimaryNodeFor(currency: widget.coin)), + ); + final _node = ref.watch( + nodeServiceChangeNotifierProvider + .select((value) => value.getNodeById(id: nodeId)), + )!; if (node?.name == _node.name) { _status = "Connected"; @@ -324,21 +165,50 @@ class _NodeCardState extends ConsumerState<NodeCard> { text: "Connect", enabled: _status == "Disconnected", onTap: () async { - final canConnect = - await _testConnection(_node, context, ref); - if (!canConnect) { - return; + final nodeFormData = NodeFormData() + ..useSSL = _node.useSSL + ..trusted = _node.trusted + ..name = _node.name + ..host = _node.host + ..login = _node.loginName + ..port = _node.port + ..isFailover = _node.isFailover; + nodeFormData.password = await _node.getPassword( + ref.read(secureStoreProvider), + ); + + if (context.mounted) { + final canConnect = await testNodeConnection( + context: context, + nodeFormData: nodeFormData, + cryptoCurrency: widget.coin, + ref: ref, + ); + + if (!canConnect) { + if (context.mounted) { + unawaited( + showFloatingFlushBar( + type: FlushBarType.warning, + iconAsset: Assets.svg.circleAlert, + message: "Could not connect to node", + context: context, + ), + ); + } + return; + } + + await ref + .read(nodeServiceChangeNotifierProvider) + .setPrimaryNodeFor( + coin: widget.coin, + node: _node, + shouldNotifyListeners: true, + ); + + await _notifyWalletsOfUpdatedNode(ref); } - - await ref - .read(nodeServiceChangeNotifierProvider) - .setPrimaryNodeFor( - coin: widget.coin, - node: _node, - shouldNotifyListeners: true, - ); - - await _notifyWalletsOfUpdatedNode(ref); }, ), const SizedBox( diff --git a/lib/widgets/node_options_sheet.dart b/lib/widgets/node_options_sheet.dart index 31bdec456..7002f7fa5 100644 --- a/lib/widgets/node_options_sheet.dart +++ b/lib/widgets/node_options_sheet.dart @@ -11,6 +11,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; +import 'package:flutter_libmonero/wownero/wownero.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; import 'package:solana/solana.dart'; @@ -26,13 +27,31 @@ import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/connection_check/electrum_connection_check.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/default_nodes.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/sync_type_enum.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/test_epic_box_connection.dart'; import 'package:stackwallet/utilities/test_eth_node_connection.dart'; import 'package:stackwallet/utilities/test_monero_node_connection.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/banano.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/bitcoin.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/bitcoin_frost.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/bitcoincash.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/dogecoin.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/ecash.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/epiccash.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/ethereum.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/firo.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/litecoin.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/monero.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/namecoin.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/nano.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/particl.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/peercoin.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/solana.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/stellar.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/tezos.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:tuple/tuple.dart'; @@ -45,7 +64,7 @@ class NodeOptionsSheet extends ConsumerWidget { }) : super(key: key); final String nodeId; - final Coin coin; + final CryptoCurrency coin; final String popBackToRoute; Future<void> _notifyWalletsOfUpdatedNode(WidgetRef ref) async { @@ -85,8 +104,8 @@ class NodeOptionsSheet extends ConsumerWidget { NodeModel node, BuildContext context, WidgetRef ref) async { bool testPassed = false; - switch (coin) { - case Coin.epicCash: + switch (coin.runtimeType) { + case const (Epiccash): try { testPassed = await testEpicNodeConnection( NodeFormData() @@ -100,14 +119,15 @@ class NodeOptionsSheet extends ConsumerWidget { } break; - case Coin.monero: - case Coin.wownero: + case const (Monero): + case const (Wownero): try { final uri = Uri.parse(node.host); if (uri.scheme.startsWith("http")) { final String path = uri.path.isEmpty ? "/json_rpc" : uri.path; - String uriString = "${uri.scheme}://${uri.host}:${node.port}$path"; + final String uriString = + "${uri.scheme}://${uri.host}:${node.port}$path"; final response = await testMoneroNodeConnection( Uri.parse(uriString), @@ -139,23 +159,16 @@ class NodeOptionsSheet extends ConsumerWidget { break; - case Coin.bitcoin: - case Coin.litecoin: - case Coin.dogecoin: - case Coin.firo: - case Coin.particl: - case Coin.bitcoinTestNet: - case Coin.firoTestNet: - case Coin.dogecoinTestNet: - case Coin.bitcoincash: - case Coin.litecoinTestNet: - case Coin.namecoin: - case Coin.bitcoincashTestnet: - case Coin.eCash: - case Coin.bitcoinFrost: - case Coin.bitcoinFrostTestNet: - case Coin.peercoin: - case Coin.peercoinTestNet: + case const (Bitcoin): + case const (Litecoin): + case const (Dogecoin): + case const (Firo): + case const (Particl): + case const (Bitcoincash): + case const (Namecoin): + case const (Ecash): + case const (BitcoinFrost): + case const (Peercoin): try { testPassed = await checkElectrumServer( host: node.host, @@ -170,7 +183,7 @@ class NodeOptionsSheet extends ConsumerWidget { break; - case Coin.ethereum: + case (Ethereum): try { testPassed = await testEthNodeConnection(node.host); } catch (_) { @@ -178,15 +191,14 @@ class NodeOptionsSheet extends ConsumerWidget { } break; - case Coin.nano: - case Coin.banano: - case Coin.tezos: - case Coin.stellar: - case Coin.stellarTestnet: + case const (Nano): + case const (Banano): + case const (Tezos): + case const (Stellar): throw UnimplementedError(); //TODO: check network/node - case Coin.solana: + case const (Solana): try { RpcClient rpcClient; if (node.host.startsWith("http") || node.host.startsWith("https")) { @@ -227,7 +239,7 @@ class NodeOptionsSheet extends ConsumerWidget { final status = ref .watch(nodeServiceChangeNotifierProvider - .select((value) => value.getPrimaryNodeFor(coin: coin))) + .select((value) => value.getPrimaryNodeFor(currency: coin))) ?.id != nodeId ? "Disconnected" diff --git a/lib/widgets/transaction_card.dart b/lib/widgets/transaction_card.dart index 6f3995002..30ab94579 100644 --- a/lib/widgets/transaction_card.dart +++ b/lib/widgets/transaction_card.dart @@ -22,10 +22,12 @@ import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount_formatter.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/format.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/epiccash.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/ethereum.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/widgets/desktop/desktop_dialog.dart'; import 'package:tuple/tuple.dart'; @@ -49,16 +51,16 @@ class _TransactionCardState extends ConsumerState<TransactionCard> { late final bool isTokenTx; late final String prefix; late final String unit; - late final Coin coin; + late final CryptoCurrency coin; late final EthContract? tokenContract; late final int minConfirms; String whatIsIt( TransactionType type, - Coin coin, + CryptoCurrency coin, int currentHeight, ) { - if (coin == Coin.epicCash && _transaction.slateId == null) { + if (coin is Epiccash && _transaction.slateId == null) { return "Restored Funds"; } @@ -169,7 +171,7 @@ class _TransactionCardState extends ConsumerState<TransactionCard> { ), ), onPressed: () async { - if (coin == Coin.epicCash && _transaction.slateId == null) { + if (coin is Epiccash && _transaction.slateId == null) { unawaited(showFloatingFlushBar( context: context, message: @@ -230,7 +232,7 @@ class _TransactionCardState extends ConsumerState<TransactionCard> { fit: BoxFit.scaleDown, child: Text( _transaction.isCancelled - ? coin == Coin.ethereum + ? coin is Ethereum ? "Failed" : "Cancelled" : whatIsIt( diff --git a/lib/widgets/wallet_info_row/sub_widgets/wallet_info_row_coin_icon.dart b/lib/widgets/wallet_info_row/sub_widgets/wallet_info_row_coin_icon.dart index 1da53d402..2424f57a8 100644 --- a/lib/widgets/wallet_info_row/sub_widgets/wallet_info_row_coin_icon.dart +++ b/lib/widgets/wallet_info_row/sub_widgets/wallet_info_row_coin_icon.dart @@ -18,19 +18,19 @@ import 'package:stackwallet/models/isar/exchange_cache/currency.dart'; import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart'; import 'package:stackwallet/services/exchange/exchange_data_loading_service.dart'; import 'package:stackwallet/themes/coin_icon_provider.dart'; -import 'package:stackwallet/themes/stack_colors.dart'; +import 'package:stackwallet/themes/theme_providers.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; class WalletInfoCoinIcon extends ConsumerWidget { const WalletInfoCoinIcon({ - Key? key, + super.key, required this.coin, this.size = 32, this.contractAddress, - }) : super(key: key); + }); - final Coin coin; + final CryptoCurrency coin; final String? contractAddress; final double size; @@ -55,10 +55,7 @@ class WalletInfoCoinIcon extends ConsumerWidget { width: size, height: size, decoration: BoxDecoration( - color: Theme.of(context) - .extension<StackColors>()! - .colorForCoin(coin) - .withOpacity(0.4), + color: ref.watch(pCoinColor(coin)).withOpacity(0.4), borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, ), diff --git a/test/address_utils_test.dart b/test/address_utils_test.dart index f1dcf1260..81bafbd9d 100644 --- a/test/address_utils_test.dart +++ b/test/address_utils_test.dart @@ -1,6 +1,5 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:stackwallet/utilities/address_utils.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; void main() { const String firoAddress = "a6ESWKz7szru5syLtYAPRhHLdKvMq3Yt1j"; diff --git a/test/cached_electrumx_test.dart b/test/cached_electrumx_test.dart index 46466163b..13c4bd3f9 100644 --- a/test/cached_electrumx_test.dart +++ b/test/cached_electrumx_test.dart @@ -4,7 +4,7 @@ import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:stackwallet/electrumx_rpc/cached_electrumx_client.dart'; import 'package:stackwallet/electrumx_rpc/electrumx_client.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; + import 'package:stackwallet/utilities/prefs.dart'; import 'cached_electrumx_test.mocks.dart'; diff --git a/test/global_events_test.dart b/test/global_events_test.dart index b5bb10a22..b45f08035 100644 --- a/test/global_events_test.dart +++ b/test/global_events_test.dart @@ -4,7 +4,6 @@ import 'package:stackwallet/services/event_bus/events/global/refresh_percent_cha import 'package:stackwallet/services/event_bus/events/global/updated_in_background_event.dart'; import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_changed_event.dart'; import 'package:stackwallet/services/event_bus/global_event_bus.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; void main() { test("NodeConnectionStatusChangedEvent", () async { diff --git a/test/services/node_service_test.dart b/test/services/node_service_test.dart index 2bd889b6e..57eaebcd6 100644 --- a/test/services/node_service_test.dart +++ b/test/services/node_service_test.dart @@ -5,7 +5,7 @@ import 'package:stackwallet/db/hive/db.dart'; import 'package:stackwallet/models/node_model.dart'; import 'package:stackwallet/services/node_service.dart'; import 'package:stackwallet/utilities/default_nodes.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; + import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'; void main() { diff --git a/test/utilities/amount/amount_unit_test.dart b/test/utilities/amount/amount_unit_test.dart index 7591473b5..e3edee615 100644 --- a/test/utilities/amount/amount_unit_test.dart +++ b/test/utilities/amount/amount_unit_test.dart @@ -2,7 +2,6 @@ import 'package:decimal/decimal.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount_unit.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; void main() { test("displayAmount BTC", () { diff --git a/test/widget_tests/address_book_card_test.dart b/test/widget_tests/address_book_card_test.dart index 1d38e6c95..581d56529 100644 --- a/test/widget_tests/address_book_card_test.dart +++ b/test/widget_tests/address_book_card_test.dart @@ -11,7 +11,7 @@ import 'package:stackwallet/pages/address_book_views/subviews/contact_popup.dart import 'package:stackwallet/providers/global/address_book_service_provider.dart'; import 'package:stackwallet/services/address_book_service.dart'; import 'package:stackwallet/themes/stack_colors.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; + import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/widgets/address_book_card.dart'; diff --git a/test/widget_tests/node_card_test.dart b/test/widget_tests/node_card_test.dart index b8e126696..faa1361f1 100644 --- a/test/widget_tests/node_card_test.dart +++ b/test/widget_tests/node_card_test.dart @@ -9,7 +9,7 @@ import 'package:stackwallet/models/node_model.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/services/node_service.dart'; import 'package:stackwallet/themes/stack_colors.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; + import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/widgets/node_card.dart'; import 'package:stackwallet/widgets/node_options_sheet.dart'; diff --git a/test/widget_tests/node_options_sheet_test.dart b/test/widget_tests/node_options_sheet_test.dart index a0d5690d3..3379742ea 100644 --- a/test/widget_tests/node_options_sheet_test.dart +++ b/test/widget_tests/node_options_sheet_test.dart @@ -11,7 +11,7 @@ import 'package:stackwallet/services/node_service.dart'; import 'package:stackwallet/services/tor_service.dart'; import 'package:stackwallet/services/wallets.dart'; import 'package:stackwallet/themes/stack_colors.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; + import 'package:stackwallet/utilities/prefs.dart'; import 'package:stackwallet/widgets/node_options_sheet.dart';