Generic enhancements (#1456)
* minor enhancement * show camera consent at least once, even if camera permission is granted already * minor enhancement [skip ci] * Add taproot derivation path to electrum_derivations.dart * remove unused import [skip ci] * Initialize Ledger only when necessary * Update app versions
Omar Hatem committed
May 22, 2024 at 04:18 UTC
7b5204fdaabd3b1f56646ba9d5fe72f22a67759c
14 files changed
+103
-72
assets/text/Release_Notes.txt
+3
-1
@@ -1 +1,3 @@
1
-Bug fixes and generic enhancements
\ No newline at end of file
1
+Add Tron wallet
2
+Hardware wallets enhancements
3
+Bug fixes
\ No newline at end of file
cw_bitcoin/lib/electrum_derivations.dart
+6
@@ -28,6 +28,12 @@ Map<DerivationType, List<DerivationInfo>> electrum_derivations = {
28
description: "Standard BIP84 native segwit",
29
scriptType: "p2wpkh",
30
),
31
+ DerivationInfo(
32
+ derivationType: DerivationType.bip39,
33
+ derivationPath: "m/86'/0'/0'",
34
+ description: "Standard BIP86 Taproot",
35
+ scriptType: "p2tr",
36
+ ),
37
DerivationInfo(
38
derivationType: DerivationType.bip39,
39
derivationPath: "m/0'",
cw_bitcoin/lib/litecoin_wallet.dart
-1
@@ -14,7 +14,6 @@ import 'package:cw_bitcoin/electrum_wallet.dart';
14
import 'package:cw_bitcoin/bitcoin_address_record.dart';
15
import 'package:cw_bitcoin/electrum_balance.dart';
16
import 'package:cw_bitcoin/litecoin_network.dart';
17
-import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
17
import 'package:bip39/bip39.dart' as bip39;
18
19
part 'litecoin_wallet.g.dart';
lib/bitcoin/cw_bitcoin.dart
+3
@@ -371,6 +371,9 @@ class CWBitcoin extends Bitcoin {
371
case "p2wpkh-p2sh":
372
address = generateP2SHAddress(hd: hd, network: network);
373
break;
374
+ case "p2tr":
375
+ address = generateP2TRAddress(hd: hd, network: network);
376
+ break;
377
default:
378
continue;
379
}
lib/buy/moonpay/moonpay_provider.dart
+13
-11
@@ -281,17 +281,19 @@ class MoonPayProvider extends BuyProvider {
281
throw Exception('Could not launch URL');
282
}
283
} catch (e) {
284
- await showDialog<void>(
285
- context: context,
286
- builder: (BuildContext context) {
287
- return AlertWithOneAction(
288
- alertTitle: 'MoonPay',
289
- alertContent: 'The MoonPay service is currently unavailable: $e',
290
- buttonText: S.of(context).ok,
291
- buttonAction: () => Navigator.of(context).pop(),
292
- );
293
- },
294
- );
284
+ if (context.mounted) {
285
+ await showDialog<void>(
286
+ context: context,
287
+ builder: (BuildContext context) {
288
+ return AlertWithOneAction(
289
+ alertTitle: 'MoonPay',
290
+ alertContent: 'The MoonPay service is currently unavailable: $e',
291
+ buttonText: S.of(context).ok,
292
+ buttonAction: () => Navigator.of(context).pop(),
293
+ );
294
+ },
295
+ );
296
+ }
297
}
298
}
299
lib/di.dart
+14
-11
@@ -330,8 +330,7 @@ Future<void> setup({
330
getIt.registerSingleton<ExchangeTemplateStore>(
331
ExchangeTemplateStore(templateSource: _exchangeTemplates));
332
getIt.registerSingleton<YatStore>(
333
- YatStore(appStore: getIt.get<AppStore>(), secureStorage: getIt.get<SecureStorage>())
334
- ..init());
333
+ YatStore(appStore: getIt.get<AppStore>(), secureStorage: getIt.get<SecureStorage>())..init());
334
getIt.registerSingleton<AnonpayTransactionsStore>(
335
AnonpayTransactionsStore(anonpayInvoiceInfoSource: _anonpayInvoiceInfoSource));
336
@@ -626,7 +625,7 @@ Future<void> setup({
625
getIt.get<BalanceViewModel>(),
626
getIt.get<ContactListViewModel>(),
627
_transactionDescriptionBox,
629
- getIt.get<LedgerViewModel>(),
628
+ getIt.get<AppStore>().wallet!.isHardwareWallet ? getIt.get<LedgerViewModel>() : null,
629
),
630
);
631
@@ -833,10 +832,14 @@ Future<void> setup({
832
isSelected: isSelected));
833
834
getIt.registerFactory<RobinhoodBuyProvider>(() => RobinhoodBuyProvider(
836
- wallet: getIt.get<AppStore>().wallet!, ledgerVM: getIt.get<LedgerViewModel>()));
835
+ wallet: getIt.get<AppStore>().wallet!,
836
+ ledgerVM:
837
+ getIt.get<AppStore>().wallet!.isHardwareWallet ? getIt.get<LedgerViewModel>() : null));
838
839
getIt.registerFactory<DFXBuyProvider>(() => DFXBuyProvider(
839
- wallet: getIt.get<AppStore>().wallet!, ledgerVM: getIt.get<LedgerViewModel>()));
840
+ wallet: getIt.get<AppStore>().wallet!,
841
+ ledgerVM:
842
+ getIt.get<AppStore>().wallet!.isHardwareWallet ? getIt.get<LedgerViewModel>() : null));
843
844
getIt.registerFactory<MoonPayProvider>(() => MoonPayProvider(
845
settingsStore: getIt.get<AppStore>().settingsStore,
@@ -937,9 +940,9 @@ Future<void> setup({
940
(derivations, _) => WalletRestoreChooseDerivationViewModel(derivationInfos: derivations));
941
942
getIt.registerFactoryParam<WalletRestoreChooseDerivationPage, List<DerivationInfo>, void>(
940
- (credentials, _) =>
943
+ (derivations, _) =>
944
WalletRestoreChooseDerivationPage(getIt.get<WalletRestoreChooseDerivationViewModel>(
942
- param1: credentials,
945
+ param1: derivations,
946
)));
947
948
getIt.registerFactoryParam<TransactionDetailsViewModel, TransactionInfo, void>(
@@ -987,8 +990,8 @@ Future<void> setup({
990
991
getIt.registerFactory(() => BackupPage(getIt.get<BackupViewModel>()));
992
990
- getIt.registerFactory(() =>
991
- EditBackupPasswordViewModel(getIt.get<SecureStorage>(), getIt.get<SecretStore>()));
993
+ getIt.registerFactory(
994
+ () => EditBackupPasswordViewModel(getIt.get<SecureStorage>(), getIt.get<SecretStore>()));
995
996
getIt.registerFactory(() => EditBackupPasswordPage(getIt.get<EditBackupPasswordViewModel>()));
997
@@ -1036,8 +1039,8 @@ Future<void> setup({
1039
1040
getIt.registerFactory(() => SupportPage(getIt.get<SupportViewModel>()));
1041
1039
- getIt.registerFactory(() => SupportChatPage(getIt.get<SupportViewModel>(),
1040
- secureStorage: getIt.get<SecureStorage>()));
1042
+ getIt.registerFactory(() =>
1043
+ SupportChatPage(getIt.get<SupportViewModel>(), secureStorage: getIt.get<SecureStorage>()));
1044
1045
getIt.registerFactory(() => SupportOtherLinksPage(getIt.get<SupportViewModel>()));
1046
lib/entities/preferences_key.dart
+1
@@ -65,6 +65,7 @@ class PreferencesKey {
65
static const lookupsUnstoppableDomains = 'looks_up_unstoppable_domain';
66
static const lookupsOpenAlias = 'looks_up_open_alias';
67
static const lookupsENS = 'looks_up_ens';
68
+ static const showCameraConsent = 'show_camera_consent';
69
70
static String moneroWalletUpdateV1Key(String name) =>
71
'${PreferencesKey.moneroWalletPasswordUpdateV1Base}_${name}';
lib/src/screens/buy/webview_page.dart
+11
-3
@@ -1,10 +1,14 @@
1
+import 'package:cake_wallet/di.dart';
2
+import 'package:cake_wallet/entities/preferences_key.dart';
3
import 'package:cake_wallet/generated/i18n.dart';
4
import 'package:cake_wallet/src/screens/base_page.dart';
5
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
6
+import 'package:cake_wallet/utils/permission_handler.dart';
7
import 'package:cake_wallet/utils/show_pop_up.dart';
8
import 'package:flutter/material.dart';
9
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
10
import 'package:permission_handler/permission_handler.dart';
11
+import 'package:shared_preferences/shared_preferences.dart';
12
13
class WebViewPage extends BasePage {
14
WebViewPage(this._title, this._url);
@@ -42,8 +46,9 @@ class WebViewPageBodyState extends State<WebViewPageBody> {
46
),
47
initialUrlRequest: URLRequest(url: WebUri.uri(widget.uri)),
48
onPermissionRequest: (controller, request) async {
45
- bool permissionGranted = await Permission.camera.status == PermissionStatus.granted;
46
- if (!permissionGranted) {
49
+ final sharedPrefs = getIt.get<SharedPreferences>();
50
+
51
+ if (sharedPrefs.getBool(PreferencesKey.showCameraConsent) ?? true) {
52
final bool userConsent = await showPopUp<bool>(
53
context: context,
54
builder: (BuildContext context) {
@@ -65,9 +70,12 @@ class WebViewPageBodyState extends State<WebViewPageBody> {
70
);
71
}
72
68
- permissionGranted = await Permission.camera.request().isGranted;
73
+ sharedPrefs.setBool(PreferencesKey.showCameraConsent, false);
74
}
75
76
+ bool permissionGranted =
77
+ await PermissionHandler.checkPermission(Permission.camera, context);
78
+
79
return PermissionResponse(
80
resources: request.resources,
81
action: permissionGranted
lib/src/screens/send/send_page.dart
+3
-4
@@ -35,7 +35,6 @@ import 'package:flutter/material.dart';
35
import 'package:flutter_mobx/flutter_mobx.dart';
36
import 'package:mobx/mobx.dart';
37
import 'package:smooth_page_indicator/smooth_page_indicator.dart';
38
-import 'package:cw_core/crypto_currency.dart';
38
import 'package:url_launcher/url_launcher.dart';
39
40
class SendPage extends BasePage {
@@ -373,17 +372,17 @@ class SendPage extends BasePage {
372
}
373
374
if (sendViewModel.wallet.isHardwareWallet) {
376
- if (!sendViewModel.ledgerViewModel.isConnected) {
375
+ if (!sendViewModel.ledgerViewModel!.isConnected) {
376
await Navigator.of(context).pushNamed(Routes.connectDevices,
377
arguments: ConnectDevicePageParams(
378
walletType: sendViewModel.walletType,
379
onConnectDevice: (BuildContext context, _) {
381
- sendViewModel.ledgerViewModel.setLedger(sendViewModel.wallet);
380
+ sendViewModel.ledgerViewModel!.setLedger(sendViewModel.wallet);
381
Navigator.of(context).pop();
382
},
383
));
384
} else {
386
- sendViewModel.ledgerViewModel.setLedger(sendViewModel.wallet);
385
+ sendViewModel.ledgerViewModel!.setLedger(sendViewModel.wallet);
386
}
387
}
388
lib/view_model/dashboard/dashboard_view_model.dart
+35
-27
@@ -329,6 +329,8 @@ abstract class DashboardViewModelBase with Store {
329
.toList();
330
}
331
332
+ bool get hasBuyProviders => ProvidersHelper.getAvailableBuyProviderTypes(wallet.type).isNotEmpty;
333
+
334
List<BuyProvider> get availableSellProviders {
335
final providerTypes = ProvidersHelper.getAvailableSellProviderTypes(wallet.type);
336
return providerTypes
@@ -338,6 +340,8 @@ abstract class DashboardViewModelBase with Store {
340
.toList();
341
}
342
343
+ bool get hasSellProviders => ProvidersHelper.getAvailableSellProviderTypes(wallet.type).isNotEmpty;
344
+
345
bool get shouldShowYatPopup => settingsStore.shouldShowYatPopup;
346
347
@action
@@ -350,13 +354,13 @@ abstract class DashboardViewModelBase with Store {
354
bool hasExchangeAction;
355
356
@computed
353
- bool get isEnabledBuyAction => !settingsStore.disableBuy && availableBuyProviders.isNotEmpty;
357
+ bool get isEnabledBuyAction => !settingsStore.disableBuy && hasBuyProviders;
358
359
@observable
360
bool hasBuyAction;
361
362
@computed
359
- bool get isEnabledSellAction => !settingsStore.disableSell && availableSellProviders.isNotEmpty;
363
+ bool get isEnabledSellAction => !settingsStore.disableSell && hasSellProviders;
364
365
@observable
366
bool hasSellAction;
@@ -495,34 +499,38 @@ abstract class DashboardViewModelBase with Store {
499
void setSyncAll(bool value) => settingsStore.currentSyncAll = value;
500
501
Future<List<String>> checkAffectedWallets() async {
498
- // await load file
499
- final vulnerableSeedsString = await rootBundle
500
- .loadString('assets/text/cakewallet_weak_bitcoin_seeds_hashed_sorted_version1.txt');
501
- final vulnerableSeeds = vulnerableSeedsString.split("\n");
502
-
503
- final walletInfoSource = await CakeHive.openBox<WalletInfo>(WalletInfo.boxName);
504
-
505
- List<String> affectedWallets = [];
506
- for (var walletInfo in walletInfoSource.values) {
507
- if (walletInfo.type == WalletType.bitcoin) {
508
- final password = await keyService.getWalletPassword(walletName: walletInfo.name);
509
- final path = await pathForWallet(name: walletInfo.name, type: walletInfo.type);
510
- final jsonSource = await read(path: path, password: password);
511
- final data = json.decode(jsonSource) as Map;
512
- final mnemonic = data['mnemonic'] as String?;
513
-
514
- if (mnemonic == null) continue;
515
-
516
- final hash = await Cryptography.instance.sha256().hash(utf8.encode(mnemonic));
517
- final seedSha = bytesToHex(hash.bytes);
518
-
519
- if (vulnerableSeeds.contains(seedSha)) {
520
- affectedWallets.add(walletInfo.name);
502
+ try {
503
+ // await load file
504
+ final vulnerableSeedsString = await rootBundle
505
+ .loadString('assets/text/cakewallet_weak_bitcoin_seeds_hashed_sorted_version1.txt');
506
+ final vulnerableSeeds = vulnerableSeedsString.split("\n");
507
+
508
+ final walletInfoSource = await CakeHive.openBox<WalletInfo>(WalletInfo.boxName);
509
+
510
+ List<String> affectedWallets = [];
511
+ for (var walletInfo in walletInfoSource.values) {
512
+ if (walletInfo.type == WalletType.bitcoin) {
513
+ final password = await keyService.getWalletPassword(walletName: walletInfo.name);
514
+ final path = await pathForWallet(name: walletInfo.name, type: walletInfo.type);
515
+ final jsonSource = await read(path: path, password: password);
516
+ final data = json.decode(jsonSource) as Map;
517
+ final mnemonic = data['mnemonic'] as String?;
518
+
519
+ if (mnemonic == null) continue;
520
+
521
+ final hash = await Cryptography.instance.sha256().hash(utf8.encode(mnemonic));
522
+ final seedSha = bytesToHex(hash.bytes);
523
+
524
+ if (vulnerableSeeds.contains(seedSha)) {
525
+ affectedWallets.add(walletInfo.name);
526
+ }
527
}
528
}
523
- }
529
525
- return affectedWallets;
530
+ return affectedWallets;
531
+ } catch (_) {
532
+ return [];
533
+ }
534
}
535
536
Future<ServicesResponse> getServicesStatus() async {
lib/view_model/send/send_view_model.dart
+2
-2
@@ -269,7 +269,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
269
final SendTemplateViewModel sendTemplateViewModel;
270
final BalanceViewModel balanceViewModel;
271
final ContactListViewModel contactListViewModel;
272
- final LedgerViewModel ledgerViewModel;
272
+ final LedgerViewModel? ledgerViewModel;
273
final FiatConversionStore _fiatConversationStore;
274
final Box<TransactionDescription> transactionDescriptionBox;
275
@@ -365,7 +365,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
365
final errorCode = e.errorCode.toRadixString(16);
366
final fallbackMsg =
367
e.message.isNotEmpty ? e.message : "Unexpected Ledger Error Code: $errorCode";
368
- final errorMsg = ledgerViewModel.interpretErrorCode(errorCode) ?? fallbackMsg;
368
+ final errorMsg = ledgerViewModel!.interpretErrorCode(errorCode) ?? fallbackMsg;
369
370
state = FailureState(errorMsg);
371
} else {
scripts/android/app_env.sh
+4
-4
@@ -15,15 +15,15 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
15
APP_ANDROID_TYPE=$1
16
17
MONERO_COM_NAME="Monero.com"
18
-MONERO_COM_VERSION="1.13.2"
19
-MONERO_COM_BUILD_NUMBER=88
18
+MONERO_COM_VERSION="1.14.0"
19
+MONERO_COM_BUILD_NUMBER=89
20
MONERO_COM_BUNDLE_ID="com.monero.app"
21
MONERO_COM_PACKAGE="com.monero.app"
22
MONERO_COM_SCHEME="monero.com"
23
24
CAKEWALLET_NAME="Cake Wallet"
25
-CAKEWALLET_VERSION="4.16.2"
26
-CAKEWALLET_BUILD_NUMBER=212
25
+CAKEWALLET_VERSION="4.17.0"
26
+CAKEWALLET_BUILD_NUMBER=213
27
CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet"
28
CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet"
29
CAKEWALLET_SCHEME="cakewallet"
scripts/ios/app_env.sh
+4
-4
@@ -13,13 +13,13 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
13
APP_IOS_TYPE=$1
14
15
MONERO_COM_NAME="Monero.com"
16
-MONERO_COM_VERSION="1.13.2"
17
-MONERO_COM_BUILD_NUMBER=86
16
+MONERO_COM_VERSION="1.14.0"
17
+MONERO_COM_BUILD_NUMBER=87
18
MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
19
20
CAKEWALLET_NAME="Cake Wallet"
21
-CAKEWALLET_VERSION="4.16.2"
22
-CAKEWALLET_BUILD_NUMBER=240
21
+CAKEWALLET_VERSION="4.17.0"
22
+CAKEWALLET_BUILD_NUMBER=244
23
CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
24
25
HAVEN_NAME="Haven"
scripts/macos/app_env.sh
+4
-4
@@ -16,13 +16,13 @@ if [ -n "$1" ]; then
16
fi
17
18
MONERO_COM_NAME="Monero.com"
19
-MONERO_COM_VERSION="1.3.2"
20
-MONERO_COM_BUILD_NUMBER=19
19
+MONERO_COM_VERSION="1.4.0"
20
+MONERO_COM_BUILD_NUMBER=20
21
MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
22
23
CAKEWALLET_NAME="Cake Wallet"
24
-CAKEWALLET_VERSION="1.9.2"
25
-CAKEWALLET_BUILD_NUMBER=73
24
+CAKEWALLET_VERSION="1.10.0"
25
+CAKEWALLET_BUILD_NUMBER=76
26
CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
27
28
if ! [[ " ${TYPES[*]} " =~ " ${APP_MACOS_TYPE} " ]]; then