diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 8fa42ac96..352b2f927 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -357,7 +357,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 19; + CURRENT_PROJECT_VERSION = 20; DEVELOPMENT_TEAM = 32J6BB6VUS; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -498,7 +498,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 19; + CURRENT_PROJECT_VERSION = 20; DEVELOPMENT_TEAM = 32J6BB6VUS; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -533,7 +533,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 19; + CURRENT_PROJECT_VERSION = 20; DEVELOPMENT_TEAM = 32J6BB6VUS; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( diff --git a/lib/bitcoin/bitcoin_transaction_credentials.dart b/lib/bitcoin/bitcoin_transaction_credentials.dart index 40f7a7aa7..0c977fef8 100644 --- a/lib/bitcoin/bitcoin_transaction_credentials.dart +++ b/lib/bitcoin/bitcoin_transaction_credentials.dart @@ -1,9 +1,9 @@ -import 'package:cake_wallet/entities/transaction_priority.dart'; +import 'package:cake_wallet/bitcoin/bitcoin_transaction_priority.dart'; class BitcoinTransactionCredentials { BitcoinTransactionCredentials(this.address, this.amount, this.priority); final String address; final String amount; - TransactionPriority priority; + BitcoinTransactionPriority priority; } diff --git a/lib/bitcoin/bitcoin_transaction_history.dart b/lib/bitcoin/bitcoin_transaction_history.dart index 09cefe5d4..16171267c 100644 --- a/lib/bitcoin/bitcoin_transaction_history.dart +++ b/lib/bitcoin/bitcoin_transaction_history.dart @@ -102,8 +102,12 @@ abstract class BitcoinTransactionHistoryBase BitcoinTransactionInfo get(String id) => transactions[id]; Future save() async { - final data = json.encode({'height': _height, 'transactions': transactions}); - await writeData(path: path, password: _password, data: data); + try { + final data = json.encode({'height': _height, 'transactions': transactions}); + await writeData(path: path, password: _password, data: data); + } catch(e) { + print('Error while save bitcoin transaction history: ${e.toString()}'); + } } @override @@ -170,6 +174,10 @@ abstract class BitcoinTransactionHistoryBase } void _updateOrInsert(BitcoinTransactionInfo transaction) { + if (transaction.id == null) { + return; + } + if (transactions[transaction.id] == null) { transactions[transaction.id] = transaction; } else { diff --git a/lib/bitcoin/bitcoin_transaction_priority.dart b/lib/bitcoin/bitcoin_transaction_priority.dart new file mode 100644 index 000000000..46dad64ee --- /dev/null +++ b/lib/bitcoin/bitcoin_transaction_priority.dart @@ -0,0 +1,29 @@ +import 'package:cake_wallet/entities/transaction_priority.dart'; + +class BitcoinTransactionPriority extends TransactionPriority { + const BitcoinTransactionPriority(this.rate, {String title, int raw}) + : super(title: title, raw: raw); + + static const List all = [slow, medium, fast]; + static const BitcoinTransactionPriority slow = BitcoinTransactionPriority(11, title: 'Slow', raw: 0); + static const BitcoinTransactionPriority medium = BitcoinTransactionPriority(90, title: 'Medium', raw: 1); + static const BitcoinTransactionPriority fast = BitcoinTransactionPriority(98, title: 'Fast', raw: 2); + + static BitcoinTransactionPriority deserialize({int raw}) { + switch (raw) { + case 0: + return slow; + case 2: + return medium; + case 3: + return fast; + default: + return null; + } + } + + final int rate; + + @override + String toString() => '$rate sat/byte'; +} diff --git a/lib/bitcoin/bitcoin_wallet.dart b/lib/bitcoin/bitcoin_wallet.dart index e5c29e240..70f4654c2 100644 --- a/lib/bitcoin/bitcoin_wallet.dart +++ b/lib/bitcoin/bitcoin_wallet.dart @@ -2,6 +2,8 @@ import 'dart:async'; import 'dart:convert'; import 'package:cake_wallet/bitcoin/address_to_output_script.dart'; import 'package:cake_wallet/bitcoin/bitcoin_mnemonic.dart'; +import 'package:cake_wallet/bitcoin/bitcoin_transaction_priority.dart'; +import 'package:cake_wallet/entities/transaction_priority.dart'; import 'package:mobx/mobx.dart'; import 'package:flutter/foundation.dart'; import 'package:rxdart/rxdart.dart'; @@ -17,7 +19,6 @@ import 'package:cake_wallet/bitcoin/script_hash.dart'; import 'package:cake_wallet/bitcoin/utils.dart'; import 'package:cake_wallet/bitcoin/bitcoin_amount_format.dart'; import 'package:cake_wallet/entities/sync_status.dart'; -import 'package:cake_wallet/entities/transaction_priority.dart'; import 'package:cake_wallet/entities/wallet_info.dart'; import 'package:cake_wallet/bitcoin/bitcoin_transaction_history.dart'; import 'package:cake_wallet/bitcoin/bitcoin_address_record.dart'; @@ -53,6 +54,7 @@ abstract class BitcoinWalletBase extends WalletBase with Store { _password = password, _accountIndex = accountIndex, super(walletInfo) { + _unspent = []; _scripthashesUpdateSubject = {}; } @@ -116,18 +118,12 @@ abstract class BitcoinWalletBase extends WalletBase with Store { walletInfo: walletInfo); } - static int feeAmountForPriority(TransactionPriority priority) { - switch (priority) { - case TransactionPriority.slow: - return 6000; - case TransactionPriority.regular: - return 22080; - case TransactionPriority.fast: - return 24000; - default: - return 0; - } - } + static int feeAmountForPriority(BitcoinTransactionPriority priority, + int inputsCount, int outputsCount) => + priority.rate * estimatedTransactionSize(inputsCount, outputsCount); + + static int estimatedTransactionSize(int inputsCount, int outputsCounts) => + inputsCount * 146 + outputsCounts * 33 + 8; @override final BitcoinTransactionHistory transactionHistory; @@ -136,6 +132,8 @@ abstract class BitcoinWalletBase extends WalletBase with Store { final ElectrumClient eclient; final String mnemonic; + List _unspent; + @override @observable String address; @@ -234,6 +232,7 @@ abstract class BitcoinWalletBase extends WalletBase with Store { }); _subscribeForUpdates(); await _updateBalance(); + await _updateUnspent(); syncStatus = SyncedSyncStatus(); } catch (e) { print(e.toString()); @@ -264,37 +263,25 @@ abstract class BitcoinWalletBase extends WalletBase with Store { Object credentials) async { final transactionCredentials = credentials as BitcoinTransactionCredentials; final inputs = []; - final fee = feeAmountForPriority(transactionCredentials.priority); + final allAmountFee = + calculateEstimatedFee(transactionCredentials.priority, null); + var fee = 0; final amount = transactionCredentials.amount != null ? stringDoubleToBitcoinAmount(transactionCredentials.amount) - : balance.confirmed - fee; - final totalAmount = amount + fee; + : balance.confirmed - allAmountFee; final txb = bitcoin.TransactionBuilder(network: bitcoin.bitcoin); final changeAddress = address; - var leftAmount = totalAmount; + var leftAmount = amount; var totalInputAmount = 0; - if (totalAmount > balance.confirmed) { - throw BitcoinTransactionWrongBalanceException(); + if (_unspent.isEmpty) { + await _updateUnspent(); } - final unspent = addresses.map((address) => eclient - .getListUnspentWithAddress(address.address) - .then((unspent) => unspent - .map((unspent) => BitcoinUnspent.fromJSON(address, unspent)))); - - for (final unptsFutures in unspent) { - final utxs = await unptsFutures; - - for (final utx in utxs) { - leftAmount = leftAmount - utx.value; - totalInputAmount += utx.value; - inputs.add(utx); - - if (leftAmount <= 0) { - break; - } - } + for (final utx in _unspent) { + leftAmount = leftAmount - utx.value; + totalInputAmount += utx.value; + inputs.add(utx); if (leftAmount <= 0) { break; @@ -305,11 +292,19 @@ abstract class BitcoinWalletBase extends WalletBase with Store { throw BitcoinTransactionNoInputsException(); } - if (amount <= 0 || totalInputAmount < amount) { + final totalAmount = amount + fee; + fee = transactionCredentials.amount != null + ? feeAmountForPriority( + transactionCredentials.priority, inputs.length, 2) + : allAmountFee; + + if (totalAmount > balance.confirmed) { throw BitcoinTransactionWrongBalanceException(); } - final changeValue = totalInputAmount - amount - fee; + if (amount <= 0 || totalInputAmount < amount) { + throw BitcoinTransactionWrongBalanceException(); + } txb.setVersion(1); @@ -330,6 +325,10 @@ abstract class BitcoinWalletBase extends WalletBase with Store { txb.addOutput( addressToOutputScript(transactionCredentials.address), amount); + final estimatedSize = estimatedTransactionSize(inputs.length, 2); + final feeAmount = transactionCredentials.priority.rate * estimatedSize; + final changeValue = totalInputAmount - amount - feeAmount; + if (changeValue > 0) { txb.addOutput(changeAddress, changeValue); } @@ -358,8 +357,30 @@ abstract class BitcoinWalletBase extends WalletBase with Store { }); @override - double calculateEstimatedFee(TransactionPriority priority) => - bitcoinAmountToDouble(amount: feeAmountForPriority(priority)); + int calculateEstimatedFee(TransactionPriority priority, int amount) { + if (priority is BitcoinTransactionPriority) { + int inputsCount = 0; + + if (amount != null) { + int totalValue = 0; + + for (final input in _unspent) { + if (totalValue >= amount) { + break; + } + + totalValue += input.value; + inputsCount += 1; + } + } else { + inputsCount = _unspent.length; + } + + return feeAmountForPriority(priority, inputsCount, 2); + } + + return 0; + } @override Future save() async { @@ -380,13 +401,26 @@ abstract class BitcoinWalletBase extends WalletBase with Store { await eclient.close(); } + Future _updateUnspent() async { + final unspent = await Future.wait(addresses.map((address) => eclient + .getListUnspentWithAddress(address.address) + .then((unspent) => unspent + .map((unspent) => BitcoinUnspent.fromJSON(address, unspent))))); + _unspent = unspent.expand((e) => e).toList(); + } + void _subscribeForUpdates() { scriptHashes.forEach((sh) async { await _scripthashesUpdateSubject[sh]?.close(); _scripthashesUpdateSubject[sh] = eclient.scripthashUpdate(sh); _scripthashesUpdateSubject[sh].listen((event) async { - await _updateBalance(); - transactionHistory.updateAsync(); + try { + await _updateBalance(); + await _updateUnspent(); + transactionHistory.updateAsync(); + } catch (e) { + print(e.toString()); + } }); }); } diff --git a/lib/bitcoin/electrum.dart b/lib/bitcoin/electrum.dart index 994264729..45e9c6b0f 100644 --- a/lib/bitcoin/electrum.dart +++ b/lib/bitcoin/electrum.dart @@ -22,8 +22,9 @@ String jsonrpcparams(List params) { } String jsonrpc( - {String method, List params, int id, double version = 2.0}) => - '{"jsonrpc": "$version", "method": "$method", "id": "$id", "params": ${json.encode(params)}}\n'; + {String method, List params, int id, double version = 2.0}) => + '{"jsonrpc": "$version", "method": "$method", "id": "$id", "params": ${json + .encode(params)}}\n'; class SocketTask { SocketTask({this.completer, this.isSubscription, this.subject}); @@ -76,7 +77,7 @@ class ElectrumClient { socket.listen((Uint8List event) { try { final response = - json.decode(utf8.decode(event.toList())) as Map; + json.decode(utf8.decode(event.toList())) as Map; _handleResponse(response); } on FormatException catch (e) { final msg = e.message.toLowerCase(); @@ -92,7 +93,7 @@ class ElectrumClient { if (isJSONStringCorrect(unterminatedString)) { final response = - json.decode(unterminatedString) as Map; + json.decode(unterminatedString) as Map; _handleResponse(response); unterminatedString = ''; } @@ -106,7 +107,7 @@ class ElectrumClient { if (isJSONStringCorrect(unterminatedString)) { final response = - json.decode(unterminatedString) as Map; + json.decode(unterminatedString) as Map; _handleResponse(response); unterminatedString = null; } @@ -172,7 +173,7 @@ class ElectrumClient { }); Future>> getListUnspentWithAddress( - String address) => + String address) => call( method: 'blockchain.scripthash.listunspent', params: [scriptHash(address)]).then((dynamic result) { @@ -252,7 +253,7 @@ class ElectrumClient { } Future broadcastTransaction( - {@required String transactionRaw}) async => + {@required String transactionRaw}) async => call(method: 'blockchain.transaction.broadcast', params: [transactionRaw]) .then((dynamic result) { if (result is String) { @@ -263,14 +264,14 @@ class ElectrumClient { }); Future> getMerkle( - {@required String hash, @required int height}) async => + {@required String hash, @required int height}) async => await call( method: 'blockchain.transaction.get_merkle', params: [hash, height]) as Map; Future> getHeader({@required int height}) async => await call(method: 'blockchain.block.get_header', params: [height]) - as Map; + as Map; Future estimatefee({@required int p}) => call(method: 'blockchain.estimatefee', params: [p]) @@ -294,10 +295,9 @@ class ElectrumClient { params: [scripthash]); } - BehaviorSubject subscribe( - {@required String id, - @required String method, - List params = const []}) { + BehaviorSubject subscribe({@required String id, + @required String method, + List params = const []}) { final subscription = BehaviorSubject(); _regisrySubscription(id, subscription); socket.write(jsonrpc(method: method, id: _id, params: params)); @@ -306,38 +306,31 @@ class ElectrumClient { } Future call({String method, List params = const []}) async { - await Future.delayed(Duration(milliseconds: 100)); final completer = Completer(); _id += 1; final id = _id; - _regisryTask(id, completer); - socket.write(jsonrpc(method: method, id: _id, params: params)); + _registryTask(id, completer); + socket.write(jsonrpc(method: method, id: id, params: params)); return completer.future; } - Future callWithTimeout( - {String method, - List params = const [], - int timeout = 2000}) async { + Future callWithTimeout({String method, + List params = const [], + int timeout = 2000}) async { final completer = Completer(); _id += 1; final id = _id; - _regisryTask(id, completer); - socket.write(jsonrpc(method: method, id: _id, params: params)); - + _registryTask(id, completer); + socket.write(jsonrpc(method: method, id: id, params: params)); Timer(Duration(milliseconds: timeout), () { if (!completer.isCompleted) { - completer.completeError(RequestFailedTimeoutException(method, _id)); + completer.completeError(RequestFailedTimeoutException(method, id)); } }); - return completer.future; - } - void request({String method, List params = const []}) { - _id += 1; - socket.write(jsonrpc(method: method, id: _id, params: params)); + return completer.future; } Future close() async { @@ -346,8 +339,9 @@ class ElectrumClient { onConnectionStatusChange = null; } - void _regisryTask(int id, Completer completer) => _tasks[id.toString()] = - SocketTask(completer: completer, isSubscription: false); + void _registryTask(int id, Completer completer) => + _tasks[id.toString()] = + SocketTask(completer: completer, isSubscription: false); void _regisrySubscription(String id, BehaviorSubject subject) => _tasks[id] = SocketTask(subject: subject, isSubscription: true); diff --git a/lib/core/backup_service.dart b/lib/core/backup_service.dart index 5851505e6..f36a67fca 100644 --- a/lib/core/backup_service.dart +++ b/lib/core/backup_service.dart @@ -149,8 +149,8 @@ class BackupService { PreferencesKey.shouldSaveRecipientAddressKey, data[PreferencesKey.shouldSaveRecipientAddressKey] as bool); await _sharedPreferences.setInt( - PreferencesKey.currentTransactionPriorityKey, - data[PreferencesKey.currentTransactionPriorityKey] as int); + PreferencesKey.currentTransactionPriorityKeyLegacy, + data[PreferencesKey.currentTransactionPriorityKeyLegacy] as int); await _sharedPreferences.setBool( PreferencesKey.allowBiometricalAuthenticationKey, data[PreferencesKey.allowBiometricalAuthenticationKey] as bool); @@ -257,8 +257,8 @@ class BackupService { _sharedPreferences.getBool(PreferencesKey.isDarkThemeLegacy), PreferencesKey.currentPinLength: _sharedPreferences.getInt(PreferencesKey.currentPinLength), - PreferencesKey.currentTransactionPriorityKey: _sharedPreferences - .getInt(PreferencesKey.currentTransactionPriorityKey), + PreferencesKey.currentTransactionPriorityKeyLegacy: _sharedPreferences + .getInt(PreferencesKey.currentTransactionPriorityKeyLegacy), PreferencesKey.allowBiometricalAuthenticationKey: _sharedPreferences .getBool(PreferencesKey.allowBiometricalAuthenticationKey), PreferencesKey.currentBitcoinElectrumSererIdKey: _sharedPreferences diff --git a/lib/core/wallet_base.dart b/lib/core/wallet_base.dart index fe187b4c7..8369ed113 100644 --- a/lib/core/wallet_base.dart +++ b/lib/core/wallet_base.dart @@ -1,16 +1,17 @@ import 'package:cake_wallet/entities/balance.dart'; +import 'package:cake_wallet/entities/transaction_priority.dart'; import 'package:flutter/foundation.dart'; import 'package:cake_wallet/entities/wallet_info.dart'; import 'package:cake_wallet/core/pending_transaction.dart'; import 'package:cake_wallet/core/transaction_history.dart'; import 'package:cake_wallet/entities/currency_for_wallet_type.dart'; -import 'package:cake_wallet/entities/transaction_priority.dart'; +import 'package:cake_wallet/entities/monero_transaction_priority.dart'; import 'package:cake_wallet/entities/crypto_currency.dart'; import 'package:cake_wallet/entities/sync_status.dart'; import 'package:cake_wallet/entities/node.dart'; import 'package:cake_wallet/entities/wallet_type.dart'; -abstract class WalletBase { +abstract class WalletBase { WalletBase(this.walletInfo); static String idFor(String name, WalletType type) => @@ -30,7 +31,7 @@ abstract class WalletBase { set address(String address); - BalaceType get balance; + BalanceType get balance; SyncStatus get syncStatus; @@ -48,7 +49,7 @@ abstract class WalletBase { Future createTransaction(Object credentials); - double calculateEstimatedFee(TransactionPriority priority); + int calculateEstimatedFee(TransactionPriority priority, int amount); Future save(); diff --git a/lib/entities/calculate_estimated_fee.dart b/lib/entities/calculate_estimated_fee.dart index 6c9200834..0f48acad3 100644 --- a/lib/entities/calculate_estimated_fee.dart +++ b/lib/entities/calculate_estimated_fee.dart @@ -1,23 +1,23 @@ -import 'package:cake_wallet/entities/transaction_priority.dart'; +import 'package:cake_wallet/entities/monero_transaction_priority.dart'; -double calculateEstimatedFee({TransactionPriority priority}) { - if (priority == TransactionPriority.slow) { +double calculateEstimatedFee({MoneroTransactionPriority priority}) { + if (priority == MoneroTransactionPriority.slow) { return 0.00002459; } - if (priority == TransactionPriority.regular) { + if (priority == MoneroTransactionPriority.regular) { return 0.00012305; } - if (priority == TransactionPriority.medium) { + if (priority == MoneroTransactionPriority.medium) { return 0.00024503; } - if (priority == TransactionPriority.fast) { + if (priority == MoneroTransactionPriority.fast) { return 0.00061453; } - if (priority == TransactionPriority.fastest) { + if (priority == MoneroTransactionPriority.fastest) { return 0.0260216; } diff --git a/lib/entities/default_settings_migration.dart b/lib/entities/default_settings_migration.dart index b1f7f4bc3..852f067e6 100644 --- a/lib/entities/default_settings_migration.dart +++ b/lib/entities/default_settings_migration.dart @@ -1,4 +1,5 @@ import 'dart:io' show File, Platform; +import 'package:cake_wallet/bitcoin/bitcoin_transaction_priority.dart'; import 'package:cake_wallet/core/generate_wallet_password.dart'; import 'package:cake_wallet/core/key_service.dart'; import 'package:cake_wallet/di.dart'; @@ -15,7 +16,7 @@ import 'package:cake_wallet/entities/node.dart'; import 'package:cake_wallet/entities/balance_display_mode.dart'; import 'package:cake_wallet/entities/fiat_currency.dart'; import 'package:cake_wallet/entities/node_list.dart'; -import 'package:cake_wallet/entities/transaction_priority.dart'; +import 'package:cake_wallet/entities/monero_transaction_priority.dart'; import 'package:cake_wallet/entities/contact.dart'; import 'package:cake_wallet/entities/fs_migration.dart'; import 'package:cake_wallet/entities/wallet_info.dart'; @@ -53,8 +54,8 @@ Future defaultSettingsMigration( PreferencesKey.currentFiatCurrencyKey, FiatCurrency.usd.toString()); await sharedPreferences.setInt( - PreferencesKey.currentTransactionPriorityKey, - TransactionPriority.standard.raw); + PreferencesKey.currentTransactionPriorityKeyLegacy, + MoneroTransactionPriority.standard.raw); await sharedPreferences.setInt( PreferencesKey.currentBalanceDisplayModeKey, BalanceDisplayMode.availableBalance.raw); @@ -93,6 +94,13 @@ Future defaultSettingsMigration( case 9: await generateBackupPassword(secureStorage); break; + case 10: + await changeTransactionPriorityAndFeeRateKeys(sharedPreferences); + break; + + case 11: + await changeDefaultMoneroNode(nodes, sharedPreferences); + break; default: break; @@ -253,3 +261,36 @@ Future generateBackupPassword(FlutterSecureStorage secureStorage) async { final password = encrypt.Key.fromSecureRandom(32).base16; await secureStorage.write(key: key, value: password); } + +Future changeTransactionPriorityAndFeeRateKeys( + SharedPreferences sharedPreferences) async { + final legacyTransactionPriority = sharedPreferences + .getInt(PreferencesKey.currentTransactionPriorityKeyLegacy); + await sharedPreferences.setInt( + PreferencesKey.moneroTransactionPriority, legacyTransactionPriority); + await sharedPreferences.setInt(PreferencesKey.bitcoinTransactionPriority, + BitcoinTransactionPriority.medium.serialize()); +} + +Future changeDefaultMoneroNode( + Box nodeSource, SharedPreferences sharedPreferences) async { + const cakeWalletMoneroNodeUriPattern = '.cakewallet.com'; + const newCakeWalletMoneroUri = 'xmr-node.cakewallet.com:18081'; + final currentMoneroNodeId = sharedPreferences.getInt(PreferencesKey.currentNodeIdKey); + final currentMoneroNode = nodeSource.values.firstWhere((node) => node.key == currentMoneroNodeId); + final needToReplaceCurrentMoneroNode = currentMoneroNode.uri.contains(cakeWalletMoneroNodeUriPattern); + + nodeSource.values.forEach((node) async { + if (node.type == WalletType.monero && node.uri.contains(cakeWalletMoneroNodeUriPattern)) { + await node.delete(); + } + }); + + final newCakeWalletNode = Node(uri: newCakeWalletMoneroUri, type: WalletType.monero); + + await nodeSource.add(newCakeWalletNode); + + if (needToReplaceCurrentMoneroNode) { + await sharedPreferences.setInt(PreferencesKey.currentNodeIdKey, newCakeWalletNode.key as int); + } +} diff --git a/lib/entities/monero_transaction_priority.dart b/lib/entities/monero_transaction_priority.dart new file mode 100644 index 000000000..7629cc5bc --- /dev/null +++ b/lib/entities/monero_transaction_priority.dart @@ -0,0 +1,74 @@ +import 'package:cake_wallet/entities/transaction_priority.dart'; +import 'package:cake_wallet/entities/wallet_type.dart'; +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/entities/enumerable_item.dart'; + +class MoneroTransactionPriority extends TransactionPriority { + const MoneroTransactionPriority({String title, int raw}) + : super(title: title, raw: raw); + + static const all = [ + MoneroTransactionPriority.slow, + MoneroTransactionPriority.regular, + MoneroTransactionPriority.medium, + MoneroTransactionPriority.fast, + MoneroTransactionPriority.fastest + ]; + static const slow = MoneroTransactionPriority(title: 'Slow', raw: 0); + static const regular = MoneroTransactionPriority(title: 'Regular', raw: 1); + static const medium = MoneroTransactionPriority(title: 'Medium', raw: 2); + static const fast = MoneroTransactionPriority(title: 'Fast', raw: 3); + static const fastest = MoneroTransactionPriority(title: 'Fastest', raw: 4); + static const standard = slow; + + + static List forWalletType(WalletType type) { + switch (type) { + case WalletType.monero: + return MoneroTransactionPriority.all; + case WalletType.bitcoin: + return [ + MoneroTransactionPriority.slow, + MoneroTransactionPriority.regular, + MoneroTransactionPriority.fast + ]; + default: + return []; + } + } + + static MoneroTransactionPriority deserialize({int raw}) { + switch (raw) { + case 0: + return slow; + case 1: + return regular; + case 2: + return medium; + case 3: + return fast; + case 4: + return fastest; + default: + return null; + } + } + + @override + String toString() { + switch (this) { + case MoneroTransactionPriority.slow: + return S.current.transaction_priority_slow; + case MoneroTransactionPriority.regular: + return S.current.transaction_priority_regular; + case MoneroTransactionPriority.medium: + return S.current.transaction_priority_medium; + case MoneroTransactionPriority.fast: + return S.current.transaction_priority_fast; + case MoneroTransactionPriority.fastest: + return S.current.transaction_priority_fastest; + default: + return ''; + } + } +} diff --git a/lib/entities/preferences_key.dart b/lib/entities/preferences_key.dart index bcf12bc45..15dbc2fb8 100644 --- a/lib/entities/preferences_key.dart +++ b/lib/entities/preferences_key.dart @@ -4,7 +4,7 @@ class PreferencesKey { static const currentNodeIdKey = 'current_node_id'; static const currentBitcoinElectrumSererIdKey = 'current_node_id_btc'; static const currentFiatCurrencyKey = 'current_fiat_currency'; - static const currentTransactionPriorityKey = 'current_fee_priority'; + static const currentTransactionPriorityKeyLegacy = 'current_fee_priority'; static const currentBalanceDisplayModeKey = 'current_balance_display_mode'; static const shouldSaveRecipientAddressKey = 'save_recipient_address'; static const allowBiometricalAuthenticationKey = @@ -15,4 +15,6 @@ class PreferencesKey { static const currentPinLength = 'current_pin_length'; static const currentLanguageCode = 'language_code'; static const currentDefaultSettingsMigrationVersion = 'current_default_settings_migration_version'; + static const moneroTransactionPriority = 'current_fee_priority_monero'; + static const bitcoinTransactionPriority = 'current_fee_priority_bitcoin'; } \ No newline at end of file diff --git a/lib/entities/transaction_priority.dart b/lib/entities/transaction_priority.dart index b7661dbdc..e03607329 100644 --- a/lib/entities/transaction_priority.dart +++ b/lib/entities/transaction_priority.dart @@ -1,73 +1,6 @@ -import 'package:cake_wallet/entities/wallet_type.dart'; -import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/entities/enumerable_item.dart'; -class TransactionPriority extends EnumerableItem with Serializable { - const TransactionPriority({String title, int raw}) - : super(title: title, raw: raw); - - static const all = [ - TransactionPriority.slow, - TransactionPriority.regular, - TransactionPriority.medium, - TransactionPriority.fast, - TransactionPriority.fastest - ]; - static const slow = TransactionPriority(title: 'Slow', raw: 0); - static const regular = TransactionPriority(title: 'Regular', raw: 1); - static const medium = TransactionPriority(title: 'Medium', raw: 2); - static const fast = TransactionPriority(title: 'Fast', raw: 3); - static const fastest = TransactionPriority(title: 'Fastest', raw: 4); - static const standard = slow; - - - static List forWalletType(WalletType type) { - switch (type) { - case WalletType.monero: - return TransactionPriority.all; - case WalletType.bitcoin: - return [ - TransactionPriority.slow, - TransactionPriority.regular, - TransactionPriority.fast - ]; - default: - return []; - } - } - - static TransactionPriority deserialize({int raw}) { - switch (raw) { - case 0: - return slow; - case 1: - return regular; - case 2: - return medium; - case 3: - return fast; - case 4: - return fastest; - default: - return null; - } - } - - @override - String toString() { - switch (this) { - case TransactionPriority.slow: - return S.current.transaction_priority_slow; - case TransactionPriority.regular: - return S.current.transaction_priority_regular; - case TransactionPriority.medium: - return S.current.transaction_priority_medium; - case TransactionPriority.fast: - return S.current.transaction_priority_fast; - case TransactionPriority.fastest: - return S.current.transaction_priority_fastest; - default: - return ''; - } - } +abstract class TransactionPriority extends EnumerableItem + with Serializable { + const TransactionPriority({String title, int raw}) : super(title: title, raw: raw); } diff --git a/lib/main.dart b/lib/main.dart index f7c7a3656..339833cd0 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -96,7 +96,7 @@ Future main() async { exchangeTemplates: exchangeTemplates, transactionDescriptions: transactionDescriptions, secureStorage: secureStorage, - initialMigrationVersion: 9); + initialMigrationVersion: 11); runApp(App()); } catch (e) { runApp(MaterialApp( @@ -123,7 +123,7 @@ Future initialSetup( @required Box exchangeTemplates, @required Box transactionDescriptions, FlutterSecureStorage secureStorage, - int initialMigrationVersion = 9}) async { + int initialMigrationVersion = 11}) async { await defaultSettingsMigration( secureStorage: secureStorage, version: initialMigrationVersion, diff --git a/lib/monero/monero_transaction_creation_credentials.dart b/lib/monero/monero_transaction_creation_credentials.dart index 312b37401..75d3eaa79 100644 --- a/lib/monero/monero_transaction_creation_credentials.dart +++ b/lib/monero/monero_transaction_creation_credentials.dart @@ -1,5 +1,5 @@ import 'package:cake_wallet/entities/transaction_creation_credentials.dart'; -import 'package:cake_wallet/entities/transaction_priority.dart'; +import 'package:cake_wallet/entities/monero_transaction_priority.dart'; class MoneroTransactionCreationCredentials extends TransactionCreationCredentials { @@ -9,5 +9,5 @@ class MoneroTransactionCreationCredentials final String address; final String paymentId; final String amount; - final TransactionPriority priority; + final MoneroTransactionPriority priority; } diff --git a/lib/monero/monero_wallet.dart b/lib/monero/monero_wallet.dart index df83bdb1b..0891100c8 100644 --- a/lib/monero/monero_wallet.dart +++ b/lib/monero/monero_wallet.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:cake_wallet/entities/transaction_priority.dart'; import 'package:cake_wallet/monero/monero_amount_format.dart'; import 'package:cake_wallet/monero/monero_transaction_creation_exception.dart'; import 'package:flutter/foundation.dart'; @@ -21,7 +22,7 @@ import 'package:cake_wallet/core/wallet_base.dart'; import 'package:cake_wallet/entities/sync_status.dart'; import 'package:cake_wallet/entities/wallet_info.dart'; import 'package:cake_wallet/entities/node.dart'; -import 'package:cake_wallet/entities/transaction_priority.dart'; +import 'package:cake_wallet/entities/monero_transaction_priority.dart'; part 'monero_wallet.g.dart'; @@ -212,27 +213,22 @@ abstract class MoneroWalletBase extends WalletBase with Store { } @override - double calculateEstimatedFee(TransactionPriority priority) { + int calculateEstimatedFee(TransactionPriority priority, int amount) { // FIXME: hardcoded value; - if (priority == TransactionPriority.slow) { - return 0.00002459; - } - - if (priority == TransactionPriority.regular) { - return 0.00012305; - } - - if (priority == TransactionPriority.medium) { - return 0.00024503; - } - - if (priority == TransactionPriority.fast) { - return 0.00061453; - } - - if (priority == TransactionPriority.fastest) { - return 0.0260216; + if (priority is MoneroTransactionPriority) { + switch (priority) { + case MoneroTransactionPriority.slow: + return 24590000; + case MoneroTransactionPriority.regular: + return 123050000; + case MoneroTransactionPriority.medium: + return 245029999; + case MoneroTransactionPriority.fast: + return 614530000; + case MoneroTransactionPriority.fastest: + return 26021600000; + } } return 0; diff --git a/lib/src/screens/send/send_page.dart b/lib/src/screens/send/send_page.dart index 856a4b464..22505170b 100644 --- a/lib/src/screens/send/send_page.dart +++ b/lib/src/screens/send/send_page.dart @@ -1,9 +1,11 @@ import 'dart:ui'; +import 'package:cake_wallet/entities/monero_transaction_priority.dart'; import 'package:cake_wallet/entities/transaction_priority.dart'; import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; import 'package:cake_wallet/src/widgets/keyboard_done_button.dart'; import 'package:cake_wallet/src/widgets/picker.dart'; import 'package:cake_wallet/src/widgets/template_tile.dart'; +import 'package:cake_wallet/view_model/settings/settings_view_model.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -752,7 +754,7 @@ class SendPage extends BasePage { } Future _setTransactionPriority(BuildContext context) async { - final items = TransactionPriority.forWalletType(sendViewModel.walletType); + final items = priorityForWalletType(sendViewModel.walletType); final selectedItem = items.indexOf(sendViewModel.transactionPriority); final isShowScrollThumb = items.length > 3; diff --git a/lib/store/settings_store.dart b/lib/store/settings_store.dart index be98fe736..45e2aa520 100644 --- a/lib/store/settings_store.dart +++ b/lib/store/settings_store.dart @@ -1,4 +1,6 @@ +import 'package:cake_wallet/bitcoin/bitcoin_transaction_priority.dart'; import 'package:cake_wallet/entities/preferences_key.dart'; +import 'package:cake_wallet/entities/transaction_priority.dart'; import 'package:cake_wallet/themes/theme_base.dart'; import 'package:cake_wallet/themes/theme_list.dart'; import 'package:flutter/foundation.dart'; @@ -14,7 +16,7 @@ import 'package:cake_wallet/entities/language_service.dart'; import 'package:cake_wallet/entities/balance_display_mode.dart'; import 'package:cake_wallet/entities/fiat_currency.dart'; import 'package:cake_wallet/entities/node.dart'; -import 'package:cake_wallet/entities/transaction_priority.dart'; +import 'package:cake_wallet/entities/monero_transaction_priority.dart'; import 'package:cake_wallet/entities/action_list_display_mode.dart'; part 'settings_store.g.dart'; @@ -25,7 +27,6 @@ abstract class SettingsStoreBase with Store { SettingsStoreBase( {@required SharedPreferences sharedPreferences, @required FiatCurrency initialFiatCurrency, - @required TransactionPriority initialTransactionPriority, @required BalanceDisplayMode initialBalanceDisplayMode, @required bool initialSaveRecipientAddress, @required bool initialAllowBiometricalAuthentication, @@ -35,15 +36,20 @@ abstract class SettingsStoreBase with Store { // @required String initialCurrentLocale, @required this.appVersion, @required Map nodes, + @required TransactionPriority initialBitcoinTransactionPriority, + @required TransactionPriority initialMoneroTransactionPriority, this.actionlistDisplayMode}) { fiatCurrency = initialFiatCurrency; - transactionPriority = initialTransactionPriority; balanceDisplayMode = initialBalanceDisplayMode; shouldSaveRecipientAddress = initialSaveRecipientAddress; allowBiometricalAuthentication = initialAllowBiometricalAuthentication; currentTheme = initialTheme; pinCodeLength = initialPinLength; languageCode = initialLanguageCode; + priority = ObservableMap.of({ + WalletType.monero: initialMoneroTransactionPriority, + WalletType.bitcoin: initialBitcoinTransactionPriority + }); this.nodes = ObservableMap.of(nodes); _sharedPreferences = sharedPreferences; @@ -52,11 +58,13 @@ abstract class SettingsStoreBase with Store { (FiatCurrency fiatCurrency) => sharedPreferences.setString( PreferencesKey.currentFiatCurrencyKey, fiatCurrency.serialize())); - reaction( - (_) => transactionPriority, - (TransactionPriority priority) => sharedPreferences.setInt( - PreferencesKey.currentTransactionPriorityKey, - priority.serialize())); + priority.observe((change) { + final key = change.key == WalletType.monero + ? PreferencesKey.moneroTransactionPriority + : PreferencesKey.bitcoinTransactionPriority; + + sharedPreferences.setInt(key, change.newValue.serialize()); + }); reaction( (_) => shouldSaveRecipientAddress, @@ -104,9 +112,6 @@ abstract class SettingsStoreBase with Store { @observable ObservableList actionlistDisplayMode; - @observable - TransactionPriority transactionPriority; - @observable BalanceDisplayMode balanceDisplayMode; @@ -128,6 +133,9 @@ abstract class SettingsStoreBase with Store { @observable String languageCode; + @observable + ObservableMap priority; + String appVersion; SharedPreferences _sharedPreferences; @@ -139,16 +147,28 @@ abstract class SettingsStoreBase with Store { static Future load( {@required Box nodeSource, FiatCurrency initialFiatCurrency = FiatCurrency.usd, - TransactionPriority initialTransactionPriority = TransactionPriority.slow, + MoneroTransactionPriority initialMoneroTransactionPriority = + MoneroTransactionPriority.slow, + BitcoinTransactionPriority initialBitcoinTransactionPriority = + BitcoinTransactionPriority.medium, BalanceDisplayMode initialBalanceDisplayMode = BalanceDisplayMode.availableBalance}) async { final sharedPreferences = await getIt.getAsync(); final currentFiatCurrency = FiatCurrency( symbol: sharedPreferences.getString(PreferencesKey.currentFiatCurrencyKey)); - final currentTransactionPriority = TransactionPriority.deserialize( - raw: sharedPreferences - .getInt(PreferencesKey.currentTransactionPriorityKey)); + final savedMoneroTransactionPriority = + MoneroTransactionPriority.deserialize( + raw: sharedPreferences + .getInt(PreferencesKey.moneroTransactionPriority)); + final savedBitcoinTransactionPriority = + BitcoinTransactionPriority.deserialize( + raw: sharedPreferences + .getInt(PreferencesKey.bitcoinTransactionPriority)); + final moneroTransactionPriority = + savedMoneroTransactionPriority ?? initialMoneroTransactionPriority; + final bitcoinTransactionPriority = + savedBitcoinTransactionPriority ?? initialBitcoinTransactionPriority; final currentBalanceDisplayMode = BalanceDisplayMode.deserialize( raw: sharedPreferences .getInt(PreferencesKey.currentBalanceDisplayModeKey)); @@ -193,30 +213,36 @@ abstract class SettingsStoreBase with Store { }, appVersion: packageInfo.version, initialFiatCurrency: currentFiatCurrency, - initialTransactionPriority: currentTransactionPriority, initialBalanceDisplayMode: currentBalanceDisplayMode, initialSaveRecipientAddress: shouldSaveRecipientAddress, initialAllowBiometricalAuthentication: allowBiometricalAuthentication, initialTheme: savedTheme, actionlistDisplayMode: actionListDisplayMode, initialPinLength: pinLength, - initialLanguageCode: savedLanguageCode); + initialLanguageCode: savedLanguageCode, + initialMoneroTransactionPriority: moneroTransactionPriority, + initialBitcoinTransactionPriority: bitcoinTransactionPriority); } Future reload( {@required Box nodeSource, FiatCurrency initialFiatCurrency = FiatCurrency.usd, - TransactionPriority initialTransactionPriority = TransactionPriority.slow, + MoneroTransactionPriority initialMoneroTransactionPriority = + MoneroTransactionPriority.slow, + BitcoinTransactionPriority initialBitcoinTransactionPriority = + BitcoinTransactionPriority.medium, BalanceDisplayMode initialBalanceDisplayMode = BalanceDisplayMode.availableBalance}) async { final settings = await SettingsStoreBase.load( nodeSource: nodeSource, initialBalanceDisplayMode: initialBalanceDisplayMode, initialFiatCurrency: initialFiatCurrency, - initialTransactionPriority: initialTransactionPriority); + initialMoneroTransactionPriority: initialMoneroTransactionPriority, + initialBitcoinTransactionPriority: initialBitcoinTransactionPriority); fiatCurrency = settings.fiatCurrency; actionlistDisplayMode = settings.actionlistDisplayMode; - transactionPriority = settings.transactionPriority; + priority[WalletType.monero] = initialMoneroTransactionPriority; + priority[WalletType.bitcoin] = initialBitcoinTransactionPriority; balanceDisplayMode = settings.balanceDisplayMode; shouldSaveRecipientAddress = settings.shouldSaveRecipientAddress; allowBiometricalAuthentication = settings.allowBiometricalAuthentication; diff --git a/lib/view_model/exchange/exchange_view_model.dart b/lib/view_model/exchange/exchange_view_model.dart index 3f406b1fb..41169dc4e 100644 --- a/lib/view_model/exchange/exchange_view_model.dart +++ b/lib/view_model/exchange/exchange_view_model.dart @@ -1,4 +1,5 @@ import 'package:cake_wallet/bitcoin/bitcoin_amount_format.dart'; +import 'package:cake_wallet/bitcoin/bitcoin_transaction_priority.dart'; import 'package:cake_wallet/bitcoin/bitcoin_wallet.dart'; import 'package:cake_wallet/core/wallet_base.dart'; import 'package:cake_wallet/entities/crypto_currency.dart'; @@ -302,8 +303,8 @@ abstract class ExchangeViewModelBase with Store { void calculateDepositAllAmount() { if (wallet is BitcoinWallet) { final availableBalance = wallet.balance.available; - final fee = BitcoinWalletBase.feeAmountForPriority( - _settingsStore.transactionPriority); + final priority = _settingsStore.priority[wallet.type] as BitcoinTransactionPriority; + final fee = wallet.calculateEstimatedFee(priority, null); if (availableBalance < fee || availableBalance == 0) { return; diff --git a/lib/view_model/send/send_view_model.dart b/lib/view_model/send/send_view_model.dart index 65c397f29..419d57695 100644 --- a/lib/view_model/send/send_view_model.dart +++ b/lib/view_model/send/send_view_model.dart @@ -1,6 +1,11 @@ +import 'package:cake_wallet/bitcoin/bitcoin_amount_format.dart'; +import 'package:cake_wallet/bitcoin/bitcoin_transaction_priority.dart'; import 'package:cake_wallet/entities/balance_display_mode.dart'; import 'package:cake_wallet/entities/calculate_fiat_amount_raw.dart'; import 'package:cake_wallet/entities/transaction_description.dart'; +import 'package:cake_wallet/entities/transaction_priority.dart'; +import 'package:cake_wallet/monero/monero_amount_format.dart'; +import 'package:cake_wallet/view_model/settings/settings_view_model.dart'; import 'package:hive/hive.dart'; import 'package:intl/intl.dart'; import 'package:mobx/mobx.dart'; @@ -21,7 +26,7 @@ import 'package:cake_wallet/monero/monero_transaction_creation_credentials.dart' import 'package:cake_wallet/entities/sync_status.dart'; import 'package:cake_wallet/entities/crypto_currency.dart'; import 'package:cake_wallet/entities/fiat_currency.dart'; -import 'package:cake_wallet/entities/transaction_priority.dart'; +import 'package:cake_wallet/entities/monero_transaction_priority.dart'; import 'package:cake_wallet/entities/calculate_fiat_amount.dart'; import 'package:cake_wallet/entities/wallet_type.dart'; import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart'; @@ -40,11 +45,11 @@ abstract class SendViewModelBase with Store { _cryptoNumberFormat = NumberFormat(), note = '', sendAll = false { - final _priority = _settingsStore.transactionPriority; + final priority = _settingsStore.priority[_wallet.type]; + final priorities = priorityForWalletType(_wallet.type); - if (!TransactionPriority.forWalletType(walletType).contains(_priority)) { - _settingsStore.transactionPriority = - TransactionPriority.forWalletType(walletType).first; + if (!priorityForWalletType(_wallet.type).contains(priority)) { + _settingsStore.priority[_wallet.type] = priorities.first; } _setCryptoNumMaximumFractionDigits(); @@ -69,8 +74,39 @@ abstract class SendViewModelBase with Store { bool sendAll; @computed - double get estimatedFee => - _wallet.calculateEstimatedFee(_settingsStore.transactionPriority); + double get estimatedFee { + int amount; + + if (cryptoAmount?.isNotEmpty ?? false) { + int _amount = 0; + switch (walletType) { + case WalletType.monero: + _amount = moneroParseAmount(amount: cryptoAmount); + break; + case WalletType.bitcoin: + _amount = stringDoubleToBitcoinAmount(cryptoAmount); + break; + default: + break; + } + + if (_amount > 0) { + amount = _amount; + } + } + + final fee = _wallet.calculateEstimatedFee(_settingsStore.priority[_wallet.type], amount); + + if (_wallet is BitcoinWallet) { + return bitcoinAmountToDouble(amount: fee); + } + + if (_wallet is MoneroWallet) { + return moneroAmountToDouble(amount: fee); + } + + return 0; + } @computed String get estimatedFeeFiatAmount { @@ -119,7 +155,7 @@ abstract class SendViewModelBase with Store { FiatCurrency get fiat => _settingsStore.fiatCurrency; TransactionPriority get transactionPriority => - _settingsStore.transactionPriority; + _settingsStore.priority[_wallet.type]; CryptoCurrency get currency => _wallet.currency; @@ -213,7 +249,7 @@ abstract class SendViewModelBase with Store { @action void setTransactionPriority(TransactionPriority priority) => - _settingsStore.transactionPriority = priority; + _settingsStore.priority[_wallet.type] = priority; Future decodeOpenaliasRecord(String name) async { final record = await OpenaliasRecord.fetchAddressAndName( @@ -257,16 +293,17 @@ abstract class SendViewModelBase with Store { switch (_wallet.type) { case WalletType.bitcoin: final amount = !sendAll ? _amount : null; + final priority = _settingsStore.priority[_wallet.type]; - return BitcoinTransactionCredentials( - address, amount, _settingsStore.transactionPriority); + return BitcoinTransactionCredentials(address, amount, priority as BitcoinTransactionPriority); case WalletType.monero: final amount = !sendAll ? _amount : null; + final priority = _settingsStore.priority[_wallet.type]; return MoneroTransactionCreationCredentials( address: address, paymentId: '', - priority: _settingsStore.transactionPriority, + priority: priority as MoneroTransactionPriority, amount: amount); default: return null; diff --git a/lib/view_model/settings/settings_view_model.dart b/lib/view_model/settings/settings_view_model.dart index 9da79b19b..3811d967b 100644 --- a/lib/view_model/settings/settings_view_model.dart +++ b/lib/view_model/settings/settings_view_model.dart @@ -1,4 +1,6 @@ +import 'package:cake_wallet/bitcoin/bitcoin_transaction_priority.dart'; import 'package:cake_wallet/entities/balance.dart'; +import 'package:cake_wallet/entities/transaction_priority.dart'; import 'package:cake_wallet/themes/theme_base.dart'; import 'package:cake_wallet/themes/theme_list.dart'; import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart'; @@ -14,7 +16,7 @@ import 'package:cake_wallet/entities/wallet_type.dart'; import 'package:cake_wallet/entities/balance_display_mode.dart'; import 'package:cake_wallet/entities/fiat_currency.dart'; import 'package:cake_wallet/entities/node.dart'; -import 'package:cake_wallet/entities/transaction_priority.dart'; +import 'package:cake_wallet/entities/monero_transaction_priority.dart'; import 'package:cake_wallet/entities/action_list_display_mode.dart'; import 'package:cake_wallet/view_model/settings/version_list_item.dart'; import 'package:cake_wallet/view_model/settings/link_list_item.dart'; @@ -28,6 +30,17 @@ part 'settings_view_model.g.dart'; class SettingsViewModel = SettingsViewModelBase with _$SettingsViewModel; +List priorityForWalletType(WalletType type) { + switch (type) { + case WalletType.monero: + return MoneroTransactionPriority.all; + case WalletType.bitcoin: + return BitcoinTransactionPriority.all; + default: + return []; + } +} + abstract class SettingsViewModelBase with Store { SettingsViewModelBase(this._settingsStore, WalletBase wallet) : itemHeaders = {}, @@ -37,11 +50,11 @@ abstract class SettingsViewModelBase with Store { PackageInfo.fromPlatform().then( (PackageInfo packageInfo) => currentVersion = packageInfo.version); - final _priority = _settingsStore.transactionPriority; + final priority = _settingsStore.priority[wallet.type]; + final priorities = priorityForWalletType(wallet.type); - if (!TransactionPriority.forWalletType(_walletType).contains(_priority)) { - _settingsStore.transactionPriority = - TransactionPriority.forWalletType(_walletType).first; + if (!priorities.contains(priority)) { + _settingsStore.priority[wallet.type] = priorities.first; } sections = [ @@ -60,10 +73,10 @@ abstract class SettingsViewModelBase with Store { setFiatCurrency(currency)), PickerListItem( title: S.current.settings_fee_priority, - items: TransactionPriority.forWalletType(wallet.type), + items: priorityForWalletType(wallet.type), selectedItem: () => transactionPriority, onItemSelected: (TransactionPriority priority) => - _settingsStore.transactionPriority = priority), + _settingsStore.priority[wallet.type] = priority), SwitcherListItem( title: S.current.settings_save_recipient_address, value: () => shouldSaveRecipientAddress, @@ -182,7 +195,7 @@ abstract class SettingsViewModelBase with Store { @computed TransactionPriority get transactionPriority => - _settingsStore.transactionPriority; + _settingsStore.priority[_walletType]; @computed BalanceDisplayMode get balanceDisplayMode =>