CAKE-234

M committed Jan 27, 2021 at 15:51 UTC e3b8ea11285db560b323a8a65e9a7792124e5293
21 files changed +427 -236
ios/Runner.xcodeproj/project.pbxproj
+3 -3
@@ -357,7 +357,7 @@
357 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
358 CLANG_ENABLE_MODULES = YES;
359 CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
360 - CURRENT_PROJECT_VERSION = 19;
360 + CURRENT_PROJECT_VERSION = 20;
361 DEVELOPMENT_TEAM = 32J6BB6VUS;
362 ENABLE_BITCODE = NO;
363 FRAMEWORK_SEARCH_PATHS = (
@@ -498,7 +498,7 @@
498 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
499 CLANG_ENABLE_MODULES = YES;
500 CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
501 - CURRENT_PROJECT_VERSION = 19;
501 + CURRENT_PROJECT_VERSION = 20;
502 DEVELOPMENT_TEAM = 32J6BB6VUS;
503 ENABLE_BITCODE = NO;
504 FRAMEWORK_SEARCH_PATHS = (
@@ -533,7 +533,7 @@
533 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
534 CLANG_ENABLE_MODULES = YES;
535 CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
536 - CURRENT_PROJECT_VERSION = 19;
536 + CURRENT_PROJECT_VERSION = 20;
537 DEVELOPMENT_TEAM = 32J6BB6VUS;
538 ENABLE_BITCODE = NO;
539 FRAMEWORK_SEARCH_PATHS = (
lib/bitcoin/bitcoin_transaction_credentials.dart
+2 -2
@@ -1,9 +1,9 @@
1 -import 'package:cake_wallet/entities/transaction_priority.dart';
1 +import 'package:cake_wallet/bitcoin/bitcoin_transaction_priority.dart';
2
3 class BitcoinTransactionCredentials {
4 BitcoinTransactionCredentials(this.address, this.amount, this.priority);
5
6 final String address;
7 final String amount;
8 - TransactionPriority priority;
8 + BitcoinTransactionPriority priority;
9 }
lib/bitcoin/bitcoin_transaction_history.dart
+10 -2
@@ -102,8 +102,12 @@ abstract class BitcoinTransactionHistoryBase
102 BitcoinTransactionInfo get(String id) => transactions[id];
103
104 Future<void> save() async {
105 - final data = json.encode({'height': _height, 'transactions': transactions});
106 - await writeData(path: path, password: _password, data: data);
105 + try {
106 + final data = json.encode({'height': _height, 'transactions': transactions});
107 + await writeData(path: path, password: _password, data: data);
108 + } catch(e) {
109 + print('Error while save bitcoin transaction history: ${e.toString()}');
110 + }
111 }
112
113 @override
@@ -170,6 +174,10 @@ abstract class BitcoinTransactionHistoryBase
174 }
175
176 void _updateOrInsert(BitcoinTransactionInfo transaction) {
177 + if (transaction.id == null) {
178 + return;
179 + }
180 +
181 if (transactions[transaction.id] == null) {
182 transactions[transaction.id] = transaction;
183 } else {
lib/bitcoin/bitcoin_transaction_priority.dart new
+29
@@ -0,0 +1,29 @@
1 +import 'package:cake_wallet/entities/transaction_priority.dart';
2 +
3 +class BitcoinTransactionPriority extends TransactionPriority {
4 + const BitcoinTransactionPriority(this.rate, {String title, int raw})
5 + : super(title: title, raw: raw);
6 +
7 + static const List<BitcoinTransactionPriority> all = [slow, medium, fast];
8 + static const BitcoinTransactionPriority slow = BitcoinTransactionPriority(11, title: 'Slow', raw: 0);
9 + static const BitcoinTransactionPriority medium = BitcoinTransactionPriority(90, title: 'Medium', raw: 1);
10 + static const BitcoinTransactionPriority fast = BitcoinTransactionPriority(98, title: 'Fast', raw: 2);
11 +
12 + static BitcoinTransactionPriority deserialize({int raw}) {
13 + switch (raw) {
14 + case 0:
15 + return slow;
16 + case 2:
17 + return medium;
18 + case 3:
19 + return fast;
20 + default:
21 + return null;
22 + }
23 + }
24 +
25 + final int rate;
26 +
27 + @override
28 + String toString() => '$rate sat/byte';
29 +}
lib/bitcoin/bitcoin_wallet.dart
+76 -42
@@ -2,6 +2,8 @@ import 'dart:async';
2 import 'dart:convert';
3 import 'package:cake_wallet/bitcoin/address_to_output_script.dart';
4 import 'package:cake_wallet/bitcoin/bitcoin_mnemonic.dart';
5 +import 'package:cake_wallet/bitcoin/bitcoin_transaction_priority.dart';
6 +import 'package:cake_wallet/entities/transaction_priority.dart';
7 import 'package:mobx/mobx.dart';
8 import 'package:flutter/foundation.dart';
9 import 'package:rxdart/rxdart.dart';
@@ -17,7 +19,6 @@ import 'package:cake_wallet/bitcoin/script_hash.dart';
19 import 'package:cake_wallet/bitcoin/utils.dart';
20 import 'package:cake_wallet/bitcoin/bitcoin_amount_format.dart';
21 import 'package:cake_wallet/entities/sync_status.dart';
20 -import 'package:cake_wallet/entities/transaction_priority.dart';
22 import 'package:cake_wallet/entities/wallet_info.dart';
23 import 'package:cake_wallet/bitcoin/bitcoin_transaction_history.dart';
24 import 'package:cake_wallet/bitcoin/bitcoin_address_record.dart';
@@ -53,6 +54,7 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
54 _password = password,
55 _accountIndex = accountIndex,
56 super(walletInfo) {
57 + _unspent = [];
58 _scripthashesUpdateSubject = {};
59 }
60
@@ -116,18 +118,12 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
118 walletInfo: walletInfo);
119 }
120
119 - static int feeAmountForPriority(TransactionPriority priority) {
120 - switch (priority) {
121 - case TransactionPriority.slow:
122 - return 6000;
123 - case TransactionPriority.regular:
124 - return 22080;
125 - case TransactionPriority.fast:
126 - return 24000;
127 - default:
128 - return 0;
129 - }
130 - }
121 + static int feeAmountForPriority(BitcoinTransactionPriority priority,
122 + int inputsCount, int outputsCount) =>
123 + priority.rate * estimatedTransactionSize(inputsCount, outputsCount);
124 +
125 + static int estimatedTransactionSize(int inputsCount, int outputsCounts) =>
126 + inputsCount * 146 + outputsCounts * 33 + 8;
127
128 @override
129 final BitcoinTransactionHistory transactionHistory;
@@ -136,6 +132,8 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
132 final ElectrumClient eclient;
133 final String mnemonic;
134
135 + List<BitcoinUnspent> _unspent;
136 +
137 @override
138 @observable
139 String address;
@@ -234,6 +232,7 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
232 });
233 _subscribeForUpdates();
234 await _updateBalance();
235 + await _updateUnspent();
236 syncStatus = SyncedSyncStatus();
237 } catch (e) {
238 print(e.toString());
@@ -264,37 +263,25 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
263 Object credentials) async {
264 final transactionCredentials = credentials as BitcoinTransactionCredentials;
265 final inputs = <BitcoinUnspent>[];
267 - final fee = feeAmountForPriority(transactionCredentials.priority);
266 + final allAmountFee =
267 + calculateEstimatedFee(transactionCredentials.priority, null);
268 + var fee = 0;
269 final amount = transactionCredentials.amount != null
270 ? stringDoubleToBitcoinAmount(transactionCredentials.amount)
270 - : balance.confirmed - fee;
271 - final totalAmount = amount + fee;
271 + : balance.confirmed - allAmountFee;
272 final txb = bitcoin.TransactionBuilder(network: bitcoin.bitcoin);
273 final changeAddress = address;
274 - var leftAmount = totalAmount;
274 + var leftAmount = amount;
275 var totalInputAmount = 0;
276
277 - if (totalAmount > balance.confirmed) {
278 - throw BitcoinTransactionWrongBalanceException();
277 + if (_unspent.isEmpty) {
278 + await _updateUnspent();
279 }
280
281 - final unspent = addresses.map((address) => eclient
282 - .getListUnspentWithAddress(address.address)
283 - .then((unspent) => unspent
284 - .map((unspent) => BitcoinUnspent.fromJSON(address, unspent))));
285 -
286 - for (final unptsFutures in unspent) {
287 - final utxs = await unptsFutures;
288 -
289 - for (final utx in utxs) {
290 - leftAmount = leftAmount - utx.value;
291 - totalInputAmount += utx.value;
292 - inputs.add(utx);
293 -
294 - if (leftAmount <= 0) {
295 - break;
296 - }
297 - }
281 + for (final utx in _unspent) {
282 + leftAmount = leftAmount - utx.value;
283 + totalInputAmount += utx.value;
284 + inputs.add(utx);
285
286 if (leftAmount <= 0) {
287 break;
@@ -305,11 +292,19 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
292 throw BitcoinTransactionNoInputsException();
293 }
294
308 - if (amount <= 0 || totalInputAmount < amount) {
295 + final totalAmount = amount + fee;
296 + fee = transactionCredentials.amount != null
297 + ? feeAmountForPriority(
298 + transactionCredentials.priority, inputs.length, 2)
299 + : allAmountFee;
300 +
301 + if (totalAmount > balance.confirmed) {
302 throw BitcoinTransactionWrongBalanceException();
303 }
304
312 - final changeValue = totalInputAmount - amount - fee;
305 + if (amount <= 0 || totalInputAmount < amount) {
306 + throw BitcoinTransactionWrongBalanceException();
307 + }
308
309 txb.setVersion(1);
310
@@ -330,6 +325,10 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
325 txb.addOutput(
326 addressToOutputScript(transactionCredentials.address), amount);
327
328 + final estimatedSize = estimatedTransactionSize(inputs.length, 2);
329 + final feeAmount = transactionCredentials.priority.rate * estimatedSize;
330 + final changeValue = totalInputAmount - amount - feeAmount;
331 +
332 if (changeValue > 0) {
333 txb.addOutput(changeAddress, changeValue);
334 }
@@ -358,8 +357,30 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
357 });
358
359 @override
361 - double calculateEstimatedFee(TransactionPriority priority) =>
362 - bitcoinAmountToDouble(amount: feeAmountForPriority(priority));
360 + int calculateEstimatedFee(TransactionPriority priority, int amount) {
361 + if (priority is BitcoinTransactionPriority) {
362 + int inputsCount = 0;
363 +
364 + if (amount != null) {
365 + int totalValue = 0;
366 +
367 + for (final input in _unspent) {
368 + if (totalValue >= amount) {
369 + break;
370 + }
371 +
372 + totalValue += input.value;
373 + inputsCount += 1;
374 + }
375 + } else {
376 + inputsCount = _unspent.length;
377 + }
378 +
379 + return feeAmountForPriority(priority, inputsCount, 2);
380 + }
381 +
382 + return 0;
383 + }
384
385 @override
386 Future<void> save() async {
@@ -380,13 +401,26 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
401 await eclient.close();
402 }
403
404 + Future<void> _updateUnspent() async {
405 + final unspent = await Future.wait(addresses.map((address) => eclient
406 + .getListUnspentWithAddress(address.address)
407 + .then((unspent) => unspent
408 + .map((unspent) => BitcoinUnspent.fromJSON(address, unspent)))));
409 + _unspent = unspent.expand((e) => e).toList();
410 + }
411 +
412 void _subscribeForUpdates() {
413 scriptHashes.forEach((sh) async {
414 await _scripthashesUpdateSubject[sh]?.close();
415 _scripthashesUpdateSubject[sh] = eclient.scripthashUpdate(sh);
416 _scripthashesUpdateSubject[sh].listen((event) async {
388 - await _updateBalance();
389 - transactionHistory.updateAsync();
417 + try {
418 + await _updateBalance();
419 + await _updateUnspent();
420 + transactionHistory.updateAsync();
421 + } catch (e) {
422 + print(e.toString());
423 + }
424 });
425 });
426 }
lib/bitcoin/electrum.dart
+25 -31
@@ -22,8 +22,9 @@ String jsonrpcparams(List<Object> params) {
22 }
23
24 String jsonrpc(
25 - {String method, List<Object> params, int id, double version = 2.0}) =>
26 - '{"jsonrpc": "$version", "method": "$method", "id": "$id", "params": ${json.encode(params)}}\n';
25 + {String method, List<Object> params, int id, double version = 2.0}) =>
26 + '{"jsonrpc": "$version", "method": "$method", "id": "$id", "params": ${json
27 + .encode(params)}}\n';
28
29 class SocketTask {
30 SocketTask({this.completer, this.isSubscription, this.subject});
@@ -76,7 +77,7 @@ class ElectrumClient {
77 socket.listen((Uint8List event) {
78 try {
79 final response =
79 - json.decode(utf8.decode(event.toList())) as Map<String, Object>;
80 + json.decode(utf8.decode(event.toList())) as Map<String, Object>;
81 _handleResponse(response);
82 } on FormatException catch (e) {
83 final msg = e.message.toLowerCase();
@@ -92,7 +93,7 @@ class ElectrumClient {
93
94 if (isJSONStringCorrect(unterminatedString)) {
95 final response =
95 - json.decode(unterminatedString) as Map<String, Object>;
96 + json.decode(unterminatedString) as Map<String, Object>;
97 _handleResponse(response);
98 unterminatedString = '';
99 }
@@ -106,7 +107,7 @@ class ElectrumClient {
107
108 if (isJSONStringCorrect(unterminatedString)) {
109 final response =
109 - json.decode(unterminatedString) as Map<String, Object>;
110 + json.decode(unterminatedString) as Map<String, Object>;
111 _handleResponse(response);
112 unterminatedString = null;
113 }
@@ -172,7 +173,7 @@ class ElectrumClient {
173 });
174
175 Future<List<Map<String, dynamic>>> getListUnspentWithAddress(
175 - String address) =>
176 + String address) =>
177 call(
178 method: 'blockchain.scripthash.listunspent',
179 params: [scriptHash(address)]).then((dynamic result) {
@@ -252,7 +253,7 @@ class ElectrumClient {
253 }
254
255 Future<String> broadcastTransaction(
255 - {@required String transactionRaw}) async =>
256 + {@required String transactionRaw}) async =>
257 call(method: 'blockchain.transaction.broadcast', params: [transactionRaw])
258 .then((dynamic result) {
259 if (result is String) {
@@ -263,14 +264,14 @@ class ElectrumClient {
264 });
265
266 Future<Map<String, dynamic>> getMerkle(
266 - {@required String hash, @required int height}) async =>
267 + {@required String hash, @required int height}) async =>
268 await call(
269 method: 'blockchain.transaction.get_merkle',
270 params: [hash, height]) as Map<String, dynamic>;
271
272 Future<Map<String, dynamic>> getHeader({@required int height}) async =>
273 await call(method: 'blockchain.block.get_header', params: [height])
273 - as Map<String, dynamic>;
274 + as Map<String, dynamic>;
275
276 Future<double> estimatefee({@required int p}) =>
277 call(method: 'blockchain.estimatefee', params: [p])
@@ -294,10 +295,9 @@ class ElectrumClient {
295 params: [scripthash]);
296 }
297
297 - BehaviorSubject<T> subscribe<T>(
298 - {@required String id,
299 - @required String method,
300 - List<Object> params = const []}) {
298 + BehaviorSubject<T> subscribe<T>({@required String id,
299 + @required String method,
300 + List<Object> params = const []}) {
301 final subscription = BehaviorSubject<T>();
302 _regisrySubscription(id, subscription);
303 socket.write(jsonrpc(method: method, id: _id, params: params));
@@ -306,38 +306,31 @@ class ElectrumClient {
306 }
307
308 Future<dynamic> call({String method, List<Object> params = const []}) async {
309 - await Future<void>.delayed(Duration(milliseconds: 100));
309 final completer = Completer<dynamic>();
310 _id += 1;
311 final id = _id;
313 - _regisryTask(id, completer);
314 - socket.write(jsonrpc(method: method, id: _id, params: params));
312 + _registryTask(id, completer);
313 + socket.write(jsonrpc(method: method, id: id, params: params));
314
315 return completer.future;
316 }
317
319 - Future<dynamic> callWithTimeout(
320 - {String method,
321 - List<Object> params = const [],
322 - int timeout = 2000}) async {
318 + Future<dynamic> callWithTimeout({String method,
319 + List<Object> params = const [],
320 + int timeout = 2000}) async {
321 final completer = Completer<dynamic>();
322 _id += 1;
323 final id = _id;
326 - _regisryTask(id, completer);
327 - socket.write(jsonrpc(method: method, id: _id, params: params));
328 -
324 + _registryTask(id, completer);
325 + socket.write(jsonrpc(method: method, id: id, params: params));
326 Timer(Duration(milliseconds: timeout), () {
327 if (!completer.isCompleted) {
331 - completer.completeError(RequestFailedTimeoutException(method, _id));
328 + completer.completeError(RequestFailedTimeoutException(method, id));
329 }
330 });
331
335 - return completer.future;
336 - }
332
338 - void request({String method, List<Object> params = const []}) {
339 - _id += 1;
340 - socket.write(jsonrpc(method: method, id: _id, params: params));
333 + return completer.future;
334 }
335
336 Future<void> close() async {
@@ -346,8 +339,9 @@ class ElectrumClient {
339 onConnectionStatusChange = null;
340 }
341
349 - void _regisryTask(int id, Completer completer) => _tasks[id.toString()] =
350 - SocketTask(completer: completer, isSubscription: false);
342 + void _registryTask(int id, Completer completer) =>
343 + _tasks[id.toString()] =
344 + SocketTask(completer: completer, isSubscription: false);
345
346 void _regisrySubscription(String id, BehaviorSubject subject) =>
347 _tasks[id] = SocketTask(subject: subject, isSubscription: true);
lib/core/backup_service.dart
+4 -4
@@ -149,8 +149,8 @@ class BackupService {
149 PreferencesKey.shouldSaveRecipientAddressKey,
150 data[PreferencesKey.shouldSaveRecipientAddressKey] as bool);
151 await _sharedPreferences.setInt(
152 - PreferencesKey.currentTransactionPriorityKey,
153 - data[PreferencesKey.currentTransactionPriorityKey] as int);
152 + PreferencesKey.currentTransactionPriorityKeyLegacy,
153 + data[PreferencesKey.currentTransactionPriorityKeyLegacy] as int);
154 await _sharedPreferences.setBool(
155 PreferencesKey.allowBiometricalAuthenticationKey,
156 data[PreferencesKey.allowBiometricalAuthenticationKey] as bool);
@@ -257,8 +257,8 @@ class BackupService {
257 _sharedPreferences.getBool(PreferencesKey.isDarkThemeLegacy),
258 PreferencesKey.currentPinLength:
259 _sharedPreferences.getInt(PreferencesKey.currentPinLength),
260 - PreferencesKey.currentTransactionPriorityKey: _sharedPreferences
261 - .getInt(PreferencesKey.currentTransactionPriorityKey),
260 + PreferencesKey.currentTransactionPriorityKeyLegacy: _sharedPreferences
261 + .getInt(PreferencesKey.currentTransactionPriorityKeyLegacy),
262 PreferencesKey.allowBiometricalAuthenticationKey: _sharedPreferences
263 .getBool(PreferencesKey.allowBiometricalAuthenticationKey),
264 PreferencesKey.currentBitcoinElectrumSererIdKey: _sharedPreferences
lib/core/wallet_base.dart
+5 -4
@@ -1,16 +1,17 @@
1 import 'package:cake_wallet/entities/balance.dart';
2 +import 'package:cake_wallet/entities/transaction_priority.dart';
3 import 'package:flutter/foundation.dart';
4 import 'package:cake_wallet/entities/wallet_info.dart';
5 import 'package:cake_wallet/core/pending_transaction.dart';
6 import 'package:cake_wallet/core/transaction_history.dart';
7 import 'package:cake_wallet/entities/currency_for_wallet_type.dart';
7 -import 'package:cake_wallet/entities/transaction_priority.dart';
8 +import 'package:cake_wallet/entities/monero_transaction_priority.dart';
9 import 'package:cake_wallet/entities/crypto_currency.dart';
10 import 'package:cake_wallet/entities/sync_status.dart';
11 import 'package:cake_wallet/entities/node.dart';
12 import 'package:cake_wallet/entities/wallet_type.dart';
13
13 -abstract class WalletBase<BalaceType extends Balance> {
14 +abstract class WalletBase<BalanceType extends Balance> {
15 WalletBase(this.walletInfo);
16
17 static String idFor(String name, WalletType type) =>
@@ -30,7 +31,7 @@ abstract class WalletBase<BalaceType extends Balance> {
31
32 set address(String address);
33
33 - BalaceType get balance;
34 + BalanceType get balance;
35
36 SyncStatus get syncStatus;
37
@@ -48,7 +49,7 @@ abstract class WalletBase<BalaceType extends Balance> {
49
50 Future<PendingTransaction> createTransaction(Object credentials);
51
51 - double calculateEstimatedFee(TransactionPriority priority);
52 + int calculateEstimatedFee(TransactionPriority priority, int amount);
53
54 Future<void> save();
55
lib/entities/calculate_estimated_fee.dart
+7 -7
@@ -1,23 +1,23 @@
1 -import 'package:cake_wallet/entities/transaction_priority.dart';
1 +import 'package:cake_wallet/entities/monero_transaction_priority.dart';
2
3 -double calculateEstimatedFee({TransactionPriority priority}) {
4 - if (priority == TransactionPriority.slow) {
3 +double calculateEstimatedFee({MoneroTransactionPriority priority}) {
4 + if (priority == MoneroTransactionPriority.slow) {
5 return 0.00002459;
6 }
7
8 - if (priority == TransactionPriority.regular) {
8 + if (priority == MoneroTransactionPriority.regular) {
9 return 0.00012305;
10 }
11
12 - if (priority == TransactionPriority.medium) {
12 + if (priority == MoneroTransactionPriority.medium) {
13 return 0.00024503;
14 }
15
16 - if (priority == TransactionPriority.fast) {
16 + if (priority == MoneroTransactionPriority.fast) {
17 return 0.00061453;
18 }
19
20 - if (priority == TransactionPriority.fastest) {
20 + if (priority == MoneroTransactionPriority.fastest) {
21 return 0.0260216;
22 }
23
lib/entities/default_settings_migration.dart
+44 -3
@@ -1,4 +1,5 @@
1 import 'dart:io' show File, Platform;
2 +import 'package:cake_wallet/bitcoin/bitcoin_transaction_priority.dart';
3 import 'package:cake_wallet/core/generate_wallet_password.dart';
4 import 'package:cake_wallet/core/key_service.dart';
5 import 'package:cake_wallet/di.dart';
@@ -15,7 +16,7 @@ import 'package:cake_wallet/entities/node.dart';
16 import 'package:cake_wallet/entities/balance_display_mode.dart';
17 import 'package:cake_wallet/entities/fiat_currency.dart';
18 import 'package:cake_wallet/entities/node_list.dart';
18 -import 'package:cake_wallet/entities/transaction_priority.dart';
19 +import 'package:cake_wallet/entities/monero_transaction_priority.dart';
20 import 'package:cake_wallet/entities/contact.dart';
21 import 'package:cake_wallet/entities/fs_migration.dart';
22 import 'package:cake_wallet/entities/wallet_info.dart';
@@ -53,8 +54,8 @@ Future defaultSettingsMigration(
54 PreferencesKey.currentFiatCurrencyKey,
55 FiatCurrency.usd.toString());
56 await sharedPreferences.setInt(
56 - PreferencesKey.currentTransactionPriorityKey,
57 - TransactionPriority.standard.raw);
57 + PreferencesKey.currentTransactionPriorityKeyLegacy,
58 + MoneroTransactionPriority.standard.raw);
59 await sharedPreferences.setInt(
60 PreferencesKey.currentBalanceDisplayModeKey,
61 BalanceDisplayMode.availableBalance.raw);
@@ -93,6 +94,13 @@ Future defaultSettingsMigration(
94 case 9:
95 await generateBackupPassword(secureStorage);
96 break;
97 + case 10:
98 + await changeTransactionPriorityAndFeeRateKeys(sharedPreferences);
99 + break;
100 +
101 + case 11:
102 + await changeDefaultMoneroNode(nodes, sharedPreferences);
103 + break;
104
105 default:
106 break;
@@ -253,3 +261,36 @@ Future<void> generateBackupPassword(FlutterSecureStorage secureStorage) async {
261 final password = encrypt.Key.fromSecureRandom(32).base16;
262 await secureStorage.write(key: key, value: password);
263 }
264 +
265 +Future<void> changeTransactionPriorityAndFeeRateKeys(
266 + SharedPreferences sharedPreferences) async {
267 + final legacyTransactionPriority = sharedPreferences
268 + .getInt(PreferencesKey.currentTransactionPriorityKeyLegacy);
269 + await sharedPreferences.setInt(
270 + PreferencesKey.moneroTransactionPriority, legacyTransactionPriority);
271 + await sharedPreferences.setInt(PreferencesKey.bitcoinTransactionPriority,
272 + BitcoinTransactionPriority.medium.serialize());
273 +}
274 +
275 +Future<void> changeDefaultMoneroNode(
276 + Box<Node> nodeSource, SharedPreferences sharedPreferences) async {
277 + const cakeWalletMoneroNodeUriPattern = '.cakewallet.com';
278 + const newCakeWalletMoneroUri = 'xmr-node.cakewallet.com:18081';
279 + final currentMoneroNodeId = sharedPreferences.getInt(PreferencesKey.currentNodeIdKey);
280 + final currentMoneroNode = nodeSource.values.firstWhere((node) => node.key == currentMoneroNodeId);
281 + final needToReplaceCurrentMoneroNode = currentMoneroNode.uri.contains(cakeWalletMoneroNodeUriPattern);
282 +
283 + nodeSource.values.forEach((node) async {
284 + if (node.type == WalletType.monero && node.uri.contains(cakeWalletMoneroNodeUriPattern)) {
285 + await node.delete();
286 + }
287 + });
288 +
289 + final newCakeWalletNode = Node(uri: newCakeWalletMoneroUri, type: WalletType.monero);
290 +
291 + await nodeSource.add(newCakeWalletNode);
292 +
293 + if (needToReplaceCurrentMoneroNode) {
294 + await sharedPreferences.setInt(PreferencesKey.currentNodeIdKey, newCakeWalletNode.key as int);
295 + }
296 +}
lib/entities/monero_transaction_priority.dart new
+74
@@ -0,0 +1,74 @@
1 +import 'package:cake_wallet/entities/transaction_priority.dart';
2 +import 'package:cake_wallet/entities/wallet_type.dart';
3 +import 'package:cake_wallet/generated/i18n.dart';
4 +import 'package:cake_wallet/entities/enumerable_item.dart';
5 +
6 +class MoneroTransactionPriority extends TransactionPriority {
7 + const MoneroTransactionPriority({String title, int raw})
8 + : super(title: title, raw: raw);
9 +
10 + static const all = [
11 + MoneroTransactionPriority.slow,
12 + MoneroTransactionPriority.regular,
13 + MoneroTransactionPriority.medium,
14 + MoneroTransactionPriority.fast,
15 + MoneroTransactionPriority.fastest
16 + ];
17 + static const slow = MoneroTransactionPriority(title: 'Slow', raw: 0);
18 + static const regular = MoneroTransactionPriority(title: 'Regular', raw: 1);
19 + static const medium = MoneroTransactionPriority(title: 'Medium', raw: 2);
20 + static const fast = MoneroTransactionPriority(title: 'Fast', raw: 3);
21 + static const fastest = MoneroTransactionPriority(title: 'Fastest', raw: 4);
22 + static const standard = slow;
23 +
24 +
25 + static List<MoneroTransactionPriority> forWalletType(WalletType type) {
26 + switch (type) {
27 + case WalletType.monero:
28 + return MoneroTransactionPriority.all;
29 + case WalletType.bitcoin:
30 + return [
31 + MoneroTransactionPriority.slow,
32 + MoneroTransactionPriority.regular,
33 + MoneroTransactionPriority.fast
34 + ];
35 + default:
36 + return [];
37 + }
38 + }
39 +
40 + static MoneroTransactionPriority deserialize({int raw}) {
41 + switch (raw) {
42 + case 0:
43 + return slow;
44 + case 1:
45 + return regular;
46 + case 2:
47 + return medium;
48 + case 3:
49 + return fast;
50 + case 4:
51 + return fastest;
52 + default:
53 + return null;
54 + }
55 + }
56 +
57 + @override
58 + String toString() {
59 + switch (this) {
60 + case MoneroTransactionPriority.slow:
61 + return S.current.transaction_priority_slow;
62 + case MoneroTransactionPriority.regular:
63 + return S.current.transaction_priority_regular;
64 + case MoneroTransactionPriority.medium:
65 + return S.current.transaction_priority_medium;
66 + case MoneroTransactionPriority.fast:
67 + return S.current.transaction_priority_fast;
68 + case MoneroTransactionPriority.fastest:
69 + return S.current.transaction_priority_fastest;
70 + default:
71 + return '';
72 + }
73 + }
74 +}
lib/entities/preferences_key.dart
+3 -1
@@ -4,7 +4,7 @@ class PreferencesKey {
4 static const currentNodeIdKey = 'current_node_id';
5 static const currentBitcoinElectrumSererIdKey = 'current_node_id_btc';
6 static const currentFiatCurrencyKey = 'current_fiat_currency';
7 - static const currentTransactionPriorityKey = 'current_fee_priority';
7 + static const currentTransactionPriorityKeyLegacy = 'current_fee_priority';
8 static const currentBalanceDisplayModeKey = 'current_balance_display_mode';
9 static const shouldSaveRecipientAddressKey = 'save_recipient_address';
10 static const allowBiometricalAuthenticationKey =
@@ -15,4 +15,6 @@ class PreferencesKey {
15 static const currentPinLength = 'current_pin_length';
16 static const currentLanguageCode = 'language_code';
17 static const currentDefaultSettingsMigrationVersion = 'current_default_settings_migration_version';
18 + static const moneroTransactionPriority = 'current_fee_priority_monero';
19 + static const bitcoinTransactionPriority = 'current_fee_priority_bitcoin';
20 }
\ No newline at end of file
lib/entities/transaction_priority.dart
+3 -70
@@ -1,73 +1,6 @@
1 -import 'package:cake_wallet/entities/wallet_type.dart';
2 -import 'package:cake_wallet/generated/i18n.dart';
1 import 'package:cake_wallet/entities/enumerable_item.dart';
2
5 -class TransactionPriority extends EnumerableItem<int> with Serializable<int> {
6 - const TransactionPriority({String title, int raw})
7 - : super(title: title, raw: raw);
8 -
9 - static const all = [
10 - TransactionPriority.slow,
11 - TransactionPriority.regular,
12 - TransactionPriority.medium,
13 - TransactionPriority.fast,
14 - TransactionPriority.fastest
15 - ];
16 - static const slow = TransactionPriority(title: 'Slow', raw: 0);
17 - static const regular = TransactionPriority(title: 'Regular', raw: 1);
18 - static const medium = TransactionPriority(title: 'Medium', raw: 2);
19 - static const fast = TransactionPriority(title: 'Fast', raw: 3);
20 - static const fastest = TransactionPriority(title: 'Fastest', raw: 4);
21 - static const standard = slow;
22 -
23 -
24 - static List<TransactionPriority> forWalletType(WalletType type) {
25 - switch (type) {
26 - case WalletType.monero:
27 - return TransactionPriority.all;
28 - case WalletType.bitcoin:
29 - return [
30 - TransactionPriority.slow,
31 - TransactionPriority.regular,
32 - TransactionPriority.fast
33 - ];
34 - default:
35 - return [];
36 - }
37 - }
38 -
39 - static TransactionPriority deserialize({int raw}) {
40 - switch (raw) {
41 - case 0:
42 - return slow;
43 - case 1:
44 - return regular;
45 - case 2:
46 - return medium;
47 - case 3:
48 - return fast;
49 - case 4:
50 - return fastest;
51 - default:
52 - return null;
53 - }
54 - }
55 -
56 - @override
57 - String toString() {
58 - switch (this) {
59 - case TransactionPriority.slow:
60 - return S.current.transaction_priority_slow;
61 - case TransactionPriority.regular:
62 - return S.current.transaction_priority_regular;
63 - case TransactionPriority.medium:
64 - return S.current.transaction_priority_medium;
65 - case TransactionPriority.fast:
66 - return S.current.transaction_priority_fast;
67 - case TransactionPriority.fastest:
68 - return S.current.transaction_priority_fastest;
69 - default:
70 - return '';
71 - }
72 - }
3 +abstract class TransactionPriority extends EnumerableItem<int>
4 + with Serializable<int> {
5 + const TransactionPriority({String title, int raw}) : super(title: title, raw: raw);
6 }
lib/main.dart
+2 -2
@@ -96,7 +96,7 @@ Future<void> main() async {
96 exchangeTemplates: exchangeTemplates,
97 transactionDescriptions: transactionDescriptions,
98 secureStorage: secureStorage,
99 - initialMigrationVersion: 9);
99 + initialMigrationVersion: 11);
100 runApp(App());
101 } catch (e) {
102 runApp(MaterialApp(
@@ -123,7 +123,7 @@ Future<void> initialSetup(
123 @required Box<ExchangeTemplate> exchangeTemplates,
124 @required Box<TransactionDescription> transactionDescriptions,
125 FlutterSecureStorage secureStorage,
126 - int initialMigrationVersion = 9}) async {
126 + int initialMigrationVersion = 11}) async {
127 await defaultSettingsMigration(
128 secureStorage: secureStorage,
129 version: initialMigrationVersion,
lib/monero/monero_transaction_creation_credentials.dart
+2 -2
@@ -1,5 +1,5 @@
1 import 'package:cake_wallet/entities/transaction_creation_credentials.dart';
2 -import 'package:cake_wallet/entities/transaction_priority.dart';
2 +import 'package:cake_wallet/entities/monero_transaction_priority.dart';
3
4 class MoneroTransactionCreationCredentials
5 extends TransactionCreationCredentials {
@@ -9,5 +9,5 @@ class MoneroTransactionCreationCredentials
9 final String address;
10 final String paymentId;
11 final String amount;
12 - final TransactionPriority priority;
12 + final MoneroTransactionPriority priority;
13 }
lib/monero/monero_wallet.dart
+16 -20
@@ -1,5 +1,6 @@
1 import 'dart:async';
2
3 +import 'package:cake_wallet/entities/transaction_priority.dart';
4 import 'package:cake_wallet/monero/monero_amount_format.dart';
5 import 'package:cake_wallet/monero/monero_transaction_creation_exception.dart';
6 import 'package:flutter/foundation.dart';
@@ -21,7 +22,7 @@ import 'package:cake_wallet/core/wallet_base.dart';
22 import 'package:cake_wallet/entities/sync_status.dart';
23 import 'package:cake_wallet/entities/wallet_info.dart';
24 import 'package:cake_wallet/entities/node.dart';
24 -import 'package:cake_wallet/entities/transaction_priority.dart';
25 +import 'package:cake_wallet/entities/monero_transaction_priority.dart';
26
27 part 'monero_wallet.g.dart';
28
@@ -212,27 +213,22 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance> with Store {
213 }
214
215 @override
215 - double calculateEstimatedFee(TransactionPriority priority) {
216 + int calculateEstimatedFee(TransactionPriority priority, int amount) {
217 // FIXME: hardcoded value;
218
218 - if (priority == TransactionPriority.slow) {
219 - return 0.00002459;
220 - }
221 -
222 - if (priority == TransactionPriority.regular) {
223 - return 0.00012305;
224 - }
225 -
226 - if (priority == TransactionPriority.medium) {
227 - return 0.00024503;
228 - }
229 -
230 - if (priority == TransactionPriority.fast) {
231 - return 0.00061453;
232 - }
233 -
234 - if (priority == TransactionPriority.fastest) {
235 - return 0.0260216;
219 + if (priority is MoneroTransactionPriority) {
220 + switch (priority) {
221 + case MoneroTransactionPriority.slow:
222 + return 24590000;
223 + case MoneroTransactionPriority.regular:
224 + return 123050000;
225 + case MoneroTransactionPriority.medium:
226 + return 245029999;
227 + case MoneroTransactionPriority.fast:
228 + return 614530000;
229 + case MoneroTransactionPriority.fastest:
230 + return 26021600000;
231 + }
232 }
233
234 return 0;
lib/src/screens/send/send_page.dart
+3 -1
@@ -1,9 +1,11 @@
1 import 'dart:ui';
2 +import 'package:cake_wallet/entities/monero_transaction_priority.dart';
3 import 'package:cake_wallet/entities/transaction_priority.dart';
4 import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
5 import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
6 import 'package:cake_wallet/src/widgets/picker.dart';
7 import 'package:cake_wallet/src/widgets/template_tile.dart';
8 +import 'package:cake_wallet/view_model/settings/settings_view_model.dart';
9 import 'package:flutter/cupertino.dart';
10 import 'package:flutter/material.dart';
11 import 'package:flutter/services.dart';
@@ -752,7 +754,7 @@ class SendPage extends BasePage {
754 }
755
756 Future<void> _setTransactionPriority(BuildContext context) async {
755 - final items = TransactionPriority.forWalletType(sendViewModel.walletType);
757 + final items = priorityForWalletType(sendViewModel.walletType);
758 final selectedItem = items.indexOf(sendViewModel.transactionPriority);
759 final isShowScrollThumb = items.length > 3;
760
lib/store/settings_store.dart
+46 -20
@@ -1,4 +1,6 @@
1 +import 'package:cake_wallet/bitcoin/bitcoin_transaction_priority.dart';
2 import 'package:cake_wallet/entities/preferences_key.dart';
3 +import 'package:cake_wallet/entities/transaction_priority.dart';
4 import 'package:cake_wallet/themes/theme_base.dart';
5 import 'package:cake_wallet/themes/theme_list.dart';
6 import 'package:flutter/foundation.dart';
@@ -14,7 +16,7 @@ import 'package:cake_wallet/entities/language_service.dart';
16 import 'package:cake_wallet/entities/balance_display_mode.dart';
17 import 'package:cake_wallet/entities/fiat_currency.dart';
18 import 'package:cake_wallet/entities/node.dart';
17 -import 'package:cake_wallet/entities/transaction_priority.dart';
19 +import 'package:cake_wallet/entities/monero_transaction_priority.dart';
20 import 'package:cake_wallet/entities/action_list_display_mode.dart';
21
22 part 'settings_store.g.dart';
@@ -25,7 +27,6 @@ abstract class SettingsStoreBase with Store {
27 SettingsStoreBase(
28 {@required SharedPreferences sharedPreferences,
29 @required FiatCurrency initialFiatCurrency,
28 - @required TransactionPriority initialTransactionPriority,
30 @required BalanceDisplayMode initialBalanceDisplayMode,
31 @required bool initialSaveRecipientAddress,
32 @required bool initialAllowBiometricalAuthentication,
@@ -35,15 +36,20 @@ abstract class SettingsStoreBase with Store {
36 // @required String initialCurrentLocale,
37 @required this.appVersion,
38 @required Map<WalletType, Node> nodes,
39 + @required TransactionPriority initialBitcoinTransactionPriority,
40 + @required TransactionPriority initialMoneroTransactionPriority,
41 this.actionlistDisplayMode}) {
42 fiatCurrency = initialFiatCurrency;
40 - transactionPriority = initialTransactionPriority;
43 balanceDisplayMode = initialBalanceDisplayMode;
44 shouldSaveRecipientAddress = initialSaveRecipientAddress;
45 allowBiometricalAuthentication = initialAllowBiometricalAuthentication;
46 currentTheme = initialTheme;
47 pinCodeLength = initialPinLength;
48 languageCode = initialLanguageCode;
49 + priority = ObservableMap<WalletType, TransactionPriority>.of({
50 + WalletType.monero: initialMoneroTransactionPriority,
51 + WalletType.bitcoin: initialBitcoinTransactionPriority
52 + });
53 this.nodes = ObservableMap<WalletType, Node>.of(nodes);
54 _sharedPreferences = sharedPreferences;
55
@@ -52,11 +58,13 @@ abstract class SettingsStoreBase with Store {
58 (FiatCurrency fiatCurrency) => sharedPreferences.setString(
59 PreferencesKey.currentFiatCurrencyKey, fiatCurrency.serialize()));
60
55 - reaction(
56 - (_) => transactionPriority,
57 - (TransactionPriority priority) => sharedPreferences.setInt(
58 - PreferencesKey.currentTransactionPriorityKey,
59 - priority.serialize()));
61 + priority.observe((change) {
62 + final key = change.key == WalletType.monero
63 + ? PreferencesKey.moneroTransactionPriority
64 + : PreferencesKey.bitcoinTransactionPriority;
65 +
66 + sharedPreferences.setInt(key, change.newValue.serialize());
67 + });
68
69 reaction(
70 (_) => shouldSaveRecipientAddress,
@@ -104,9 +112,6 @@ abstract class SettingsStoreBase with Store {
112 @observable
113 ObservableList<ActionListDisplayMode> actionlistDisplayMode;
114
107 - @observable
108 - TransactionPriority transactionPriority;
109 -
115 @observable
116 BalanceDisplayMode balanceDisplayMode;
117
@@ -128,6 +133,9 @@ abstract class SettingsStoreBase with Store {
133 @observable
134 String languageCode;
135
136 + @observable
137 + ObservableMap<WalletType, TransactionPriority> priority;
138 +
139 String appVersion;
140
141 SharedPreferences _sharedPreferences;
@@ -139,16 +147,28 @@ abstract class SettingsStoreBase with Store {
147 static Future<SettingsStore> load(
148 {@required Box<Node> nodeSource,
149 FiatCurrency initialFiatCurrency = FiatCurrency.usd,
142 - TransactionPriority initialTransactionPriority = TransactionPriority.slow,
150 + MoneroTransactionPriority initialMoneroTransactionPriority =
151 + MoneroTransactionPriority.slow,
152 + BitcoinTransactionPriority initialBitcoinTransactionPriority =
153 + BitcoinTransactionPriority.medium,
154 BalanceDisplayMode initialBalanceDisplayMode =
155 BalanceDisplayMode.availableBalance}) async {
156 final sharedPreferences = await getIt.getAsync<SharedPreferences>();
157 final currentFiatCurrency = FiatCurrency(
158 symbol:
159 sharedPreferences.getString(PreferencesKey.currentFiatCurrencyKey));
149 - final currentTransactionPriority = TransactionPriority.deserialize(
150 - raw: sharedPreferences
151 - .getInt(PreferencesKey.currentTransactionPriorityKey));
160 + final savedMoneroTransactionPriority =
161 + MoneroTransactionPriority.deserialize(
162 + raw: sharedPreferences
163 + .getInt(PreferencesKey.moneroTransactionPriority));
164 + final savedBitcoinTransactionPriority =
165 + BitcoinTransactionPriority.deserialize(
166 + raw: sharedPreferences
167 + .getInt(PreferencesKey.bitcoinTransactionPriority));
168 + final moneroTransactionPriority =
169 + savedMoneroTransactionPriority ?? initialMoneroTransactionPriority;
170 + final bitcoinTransactionPriority =
171 + savedBitcoinTransactionPriority ?? initialBitcoinTransactionPriority;
172 final currentBalanceDisplayMode = BalanceDisplayMode.deserialize(
173 raw: sharedPreferences
174 .getInt(PreferencesKey.currentBalanceDisplayModeKey));
@@ -193,30 +213,36 @@ abstract class SettingsStoreBase with Store {
213 },
214 appVersion: packageInfo.version,
215 initialFiatCurrency: currentFiatCurrency,
196 - initialTransactionPriority: currentTransactionPriority,
216 initialBalanceDisplayMode: currentBalanceDisplayMode,
217 initialSaveRecipientAddress: shouldSaveRecipientAddress,
218 initialAllowBiometricalAuthentication: allowBiometricalAuthentication,
219 initialTheme: savedTheme,
220 actionlistDisplayMode: actionListDisplayMode,
221 initialPinLength: pinLength,
203 - initialLanguageCode: savedLanguageCode);
222 + initialLanguageCode: savedLanguageCode,
223 + initialMoneroTransactionPriority: moneroTransactionPriority,
224 + initialBitcoinTransactionPriority: bitcoinTransactionPriority);
225 }
226
227 Future<void> reload(
228 {@required Box<Node> nodeSource,
229 FiatCurrency initialFiatCurrency = FiatCurrency.usd,
209 - TransactionPriority initialTransactionPriority = TransactionPriority.slow,
230 + MoneroTransactionPriority initialMoneroTransactionPriority =
231 + MoneroTransactionPriority.slow,
232 + BitcoinTransactionPriority initialBitcoinTransactionPriority =
233 + BitcoinTransactionPriority.medium,
234 BalanceDisplayMode initialBalanceDisplayMode =
235 BalanceDisplayMode.availableBalance}) async {
236 final settings = await SettingsStoreBase.load(
237 nodeSource: nodeSource,
238 initialBalanceDisplayMode: initialBalanceDisplayMode,
239 initialFiatCurrency: initialFiatCurrency,
216 - initialTransactionPriority: initialTransactionPriority);
240 + initialMoneroTransactionPriority: initialMoneroTransactionPriority,
241 + initialBitcoinTransactionPriority: initialBitcoinTransactionPriority);
242 fiatCurrency = settings.fiatCurrency;
243 actionlistDisplayMode = settings.actionlistDisplayMode;
219 - transactionPriority = settings.transactionPriority;
244 + priority[WalletType.monero] = initialMoneroTransactionPriority;
245 + priority[WalletType.bitcoin] = initialBitcoinTransactionPriority;
246 balanceDisplayMode = settings.balanceDisplayMode;
247 shouldSaveRecipientAddress = settings.shouldSaveRecipientAddress;
248 allowBiometricalAuthentication = settings.allowBiometricalAuthentication;
lib/view_model/exchange/exchange_view_model.dart
+3 -2
@@ -1,4 +1,5 @@
1 import 'package:cake_wallet/bitcoin/bitcoin_amount_format.dart';
2 +import 'package:cake_wallet/bitcoin/bitcoin_transaction_priority.dart';
3 import 'package:cake_wallet/bitcoin/bitcoin_wallet.dart';
4 import 'package:cake_wallet/core/wallet_base.dart';
5 import 'package:cake_wallet/entities/crypto_currency.dart';
@@ -302,8 +303,8 @@ abstract class ExchangeViewModelBase with Store {
303 void calculateDepositAllAmount() {
304 if (wallet is BitcoinWallet) {
305 final availableBalance = wallet.balance.available;
305 - final fee = BitcoinWalletBase.feeAmountForPriority(
306 - _settingsStore.transactionPriority);
306 + final priority = _settingsStore.priority[wallet.type] as BitcoinTransactionPriority;
307 + final fee = wallet.calculateEstimatedFee(priority, null);
308
309 if (availableBalance < fee || availableBalance == 0) {
310 return;
lib/view_model/send/send_view_model.dart
+49 -12
@@ -1,6 +1,11 @@
1 +import 'package:cake_wallet/bitcoin/bitcoin_amount_format.dart';
2 +import 'package:cake_wallet/bitcoin/bitcoin_transaction_priority.dart';
3 import 'package:cake_wallet/entities/balance_display_mode.dart';
4 import 'package:cake_wallet/entities/calculate_fiat_amount_raw.dart';
5 import 'package:cake_wallet/entities/transaction_description.dart';
6 +import 'package:cake_wallet/entities/transaction_priority.dart';
7 +import 'package:cake_wallet/monero/monero_amount_format.dart';
8 +import 'package:cake_wallet/view_model/settings/settings_view_model.dart';
9 import 'package:hive/hive.dart';
10 import 'package:intl/intl.dart';
11 import 'package:mobx/mobx.dart';
@@ -21,7 +26,7 @@ import 'package:cake_wallet/monero/monero_transaction_creation_credentials.dart'
26 import 'package:cake_wallet/entities/sync_status.dart';
27 import 'package:cake_wallet/entities/crypto_currency.dart';
28 import 'package:cake_wallet/entities/fiat_currency.dart';
24 -import 'package:cake_wallet/entities/transaction_priority.dart';
29 +import 'package:cake_wallet/entities/monero_transaction_priority.dart';
30 import 'package:cake_wallet/entities/calculate_fiat_amount.dart';
31 import 'package:cake_wallet/entities/wallet_type.dart';
32 import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
@@ -40,11 +45,11 @@ abstract class SendViewModelBase with Store {
45 _cryptoNumberFormat = NumberFormat(),
46 note = '',
47 sendAll = false {
43 - final _priority = _settingsStore.transactionPriority;
48 + final priority = _settingsStore.priority[_wallet.type];
49 + final priorities = priorityForWalletType(_wallet.type);
50
45 - if (!TransactionPriority.forWalletType(walletType).contains(_priority)) {
46 - _settingsStore.transactionPriority =
47 - TransactionPriority.forWalletType(walletType).first;
51 + if (!priorityForWalletType(_wallet.type).contains(priority)) {
52 + _settingsStore.priority[_wallet.type] = priorities.first;
53 }
54
55 _setCryptoNumMaximumFractionDigits();
@@ -69,8 +74,39 @@ abstract class SendViewModelBase with Store {
74 bool sendAll;
75
76 @computed
72 - double get estimatedFee =>
73 - _wallet.calculateEstimatedFee(_settingsStore.transactionPriority);
77 + double get estimatedFee {
78 + int amount;
79 +
80 + if (cryptoAmount?.isNotEmpty ?? false) {
81 + int _amount = 0;
82 + switch (walletType) {
83 + case WalletType.monero:
84 + _amount = moneroParseAmount(amount: cryptoAmount);
85 + break;
86 + case WalletType.bitcoin:
87 + _amount = stringDoubleToBitcoinAmount(cryptoAmount);
88 + break;
89 + default:
90 + break;
91 + }
92 +
93 + if (_amount > 0) {
94 + amount = _amount;
95 + }
96 + }
97 +
98 + final fee = _wallet.calculateEstimatedFee(_settingsStore.priority[_wallet.type], amount);
99 +
100 + if (_wallet is BitcoinWallet) {
101 + return bitcoinAmountToDouble(amount: fee);
102 + }
103 +
104 + if (_wallet is MoneroWallet) {
105 + return moneroAmountToDouble(amount: fee);
106 + }
107 +
108 + return 0;
109 + }
110
111 @computed
112 String get estimatedFeeFiatAmount {
@@ -119,7 +155,7 @@ abstract class SendViewModelBase with Store {
155 FiatCurrency get fiat => _settingsStore.fiatCurrency;
156
157 TransactionPriority get transactionPriority =>
122 - _settingsStore.transactionPriority;
158 + _settingsStore.priority[_wallet.type];
159
160 CryptoCurrency get currency => _wallet.currency;
161
@@ -213,7 +249,7 @@ abstract class SendViewModelBase with Store {
249
250 @action
251 void setTransactionPriority(TransactionPriority priority) =>
216 - _settingsStore.transactionPriority = priority;
252 + _settingsStore.priority[_wallet.type] = priority;
253
254 Future<OpenaliasRecord> decodeOpenaliasRecord(String name) async {
255 final record = await OpenaliasRecord.fetchAddressAndName(
@@ -257,16 +293,17 @@ abstract class SendViewModelBase with Store {
293 switch (_wallet.type) {
294 case WalletType.bitcoin:
295 final amount = !sendAll ? _amount : null;
296 + final priority = _settingsStore.priority[_wallet.type];
297
261 - return BitcoinTransactionCredentials(
262 - address, amount, _settingsStore.transactionPriority);
298 + return BitcoinTransactionCredentials(address, amount, priority as BitcoinTransactionPriority);
299 case WalletType.monero:
300 final amount = !sendAll ? _amount : null;
301 + final priority = _settingsStore.priority[_wallet.type];
302
303 return MoneroTransactionCreationCredentials(
304 address: address,
305 paymentId: '',
269 - priority: _settingsStore.transactionPriority,
306 + priority: priority as MoneroTransactionPriority,
307 amount: amount);
308 default:
309 return null;
lib/view_model/settings/settings_view_model.dart
+21 -8
@@ -1,4 +1,6 @@
1 +import 'package:cake_wallet/bitcoin/bitcoin_transaction_priority.dart';
2 import 'package:cake_wallet/entities/balance.dart';
3 +import 'package:cake_wallet/entities/transaction_priority.dart';
4 import 'package:cake_wallet/themes/theme_base.dart';
5 import 'package:cake_wallet/themes/theme_list.dart';
6 import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart';
@@ -14,7 +16,7 @@ import 'package:cake_wallet/entities/wallet_type.dart';
16 import 'package:cake_wallet/entities/balance_display_mode.dart';
17 import 'package:cake_wallet/entities/fiat_currency.dart';
18 import 'package:cake_wallet/entities/node.dart';
17 -import 'package:cake_wallet/entities/transaction_priority.dart';
19 +import 'package:cake_wallet/entities/monero_transaction_priority.dart';
20 import 'package:cake_wallet/entities/action_list_display_mode.dart';
21 import 'package:cake_wallet/view_model/settings/version_list_item.dart';
22 import 'package:cake_wallet/view_model/settings/link_list_item.dart';
@@ -28,6 +30,17 @@ part 'settings_view_model.g.dart';
30
31 class SettingsViewModel = SettingsViewModelBase with _$SettingsViewModel;
32
33 +List<TransactionPriority> priorityForWalletType(WalletType type) {
34 + switch (type) {
35 + case WalletType.monero:
36 + return MoneroTransactionPriority.all;
37 + case WalletType.bitcoin:
38 + return BitcoinTransactionPriority.all;
39 + default:
40 + return [];
41 + }
42 +}
43 +
44 abstract class SettingsViewModelBase with Store {
45 SettingsViewModelBase(this._settingsStore, WalletBase<Balance> wallet)
46 : itemHeaders = {},
@@ -37,11 +50,11 @@ abstract class SettingsViewModelBase with Store {
50 PackageInfo.fromPlatform().then(
51 (PackageInfo packageInfo) => currentVersion = packageInfo.version);
52
40 - final _priority = _settingsStore.transactionPriority;
53 + final priority = _settingsStore.priority[wallet.type];
54 + final priorities = priorityForWalletType(wallet.type);
55
42 - if (!TransactionPriority.forWalletType(_walletType).contains(_priority)) {
43 - _settingsStore.transactionPriority =
44 - TransactionPriority.forWalletType(_walletType).first;
56 + if (!priorities.contains(priority)) {
57 + _settingsStore.priority[wallet.type] = priorities.first;
58 }
59
60 sections = [
@@ -60,10 +73,10 @@ abstract class SettingsViewModelBase with Store {
73 setFiatCurrency(currency)),
74 PickerListItem(
75 title: S.current.settings_fee_priority,
63 - items: TransactionPriority.forWalletType(wallet.type),
76 + items: priorityForWalletType(wallet.type),
77 selectedItem: () => transactionPriority,
78 onItemSelected: (TransactionPriority priority) =>
66 - _settingsStore.transactionPriority = priority),
79 + _settingsStore.priority[wallet.type] = priority),
80 SwitcherListItem(
81 title: S.current.settings_save_recipient_address,
82 value: () => shouldSaveRecipientAddress,
@@ -182,7 +195,7 @@ abstract class SettingsViewModelBase with Store {
195
196 @computed
197 TransactionPriority get transactionPriority =>
185 - _settingsStore.transactionPriority;
198 + _settingsStore.priority[_walletType];
199
200 @computed
201 BalanceDisplayMode get balanceDisplayMode =>