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 =>