From e6b4b08c24c1c2fb6987dcca233a3fee67c50d25 Mon Sep 17 00:00:00 2001 From: Matthew Fosse Date: Thu, 18 Apr 2024 10:00:24 -0700 Subject: [PATCH 01/17] version bump to 3.13.9, auth working on mac (#1367) * version bump to 3.13.9, auth working on mac * bump flutter version in workflow file * workflow fix * test fix * downgrade flutter version * test fix * test fix * update gradle version * fixes for updated dart version, localization file updates * remove accidental inclusion * missed some unimplemented throws --- .github/workflows/pr_test_build.yml | 2 +- android/build.gradle | 2 +- cw_bitcoin/pubspec.yaml | 5 +- cw_bitcoin_cash/pubspec.yaml | 5 +- cw_core/pubspec.yaml | 5 +- cw_ethereum/pubspec.yaml | 6 +- cw_evm/pubspec.yaml | 5 +- cw_haven/pubspec.yaml | 5 +- cw_monero/pubspec.yaml | 5 +- cw_nano/pubspec.yaml | 5 +- cw_polygon/pubspec.yaml | 5 +- cw_solana/pubspec.yaml | 5 +- lib/entities/biometric_auth.dart | 26 +- lib/locales/hausa_intl.dart | 64 ++ lib/locales/yoruba_intl.dart | 937 ++++++++++-------- .../settings/security_backup_page.dart | 4 +- lib/src/screens/settings/tor_page.dart | 4 +- .../validable_annotated_editable_text.dart | 14 +- lib/view_model/auth_view_model.dart | 15 +- pubspec_base.yaml | 2 +- pubspec_description.yaml | 2 +- 21 files changed, 642 insertions(+), 481 deletions(-) diff --git a/.github/workflows/pr_test_build.yml b/.github/workflows/pr_test_build.yml index dc231df42..bfa378342 100644 --- a/.github/workflows/pr_test_build.yml +++ b/.github/workflows/pr_test_build.yml @@ -42,7 +42,7 @@ jobs: - name: Flutter action uses: subosito/flutter-action@v1 with: - flutter-version: "3.10.x" + flutter-version: "3.13.9" channel: stable - name: Install package dependencies diff --git a/android/build.gradle b/android/build.gradle index 8286d9cb9..e182e39af 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '1.7.10' + ext.kotlin_version = '1.8.10' repositories { google() jcenter() diff --git a/cw_bitcoin/pubspec.yaml b/cw_bitcoin/pubspec.yaml index 632a3140a..1ccdb70c9 100644 --- a/cw_bitcoin/pubspec.yaml +++ b/cw_bitcoin/pubspec.yaml @@ -39,11 +39,14 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - build_runner: ^2.1.11 + build_runner: ^2.4.7 build_resolvers: ^2.0.9 mobx_codegen: ^2.0.7 hive_generator: ^1.1.3 +dependency_overrides: + watcher: ^1.1.0 + # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/cw_bitcoin_cash/pubspec.yaml b/cw_bitcoin_cash/pubspec.yaml index 37827f1ba..ceef539c3 100644 --- a/cw_bitcoin_cash/pubspec.yaml +++ b/cw_bitcoin_cash/pubspec.yaml @@ -39,10 +39,13 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - build_runner: ^2.1.11 + build_runner: ^2.4.7 mobx_codegen: ^2.0.7 hive_generator: ^1.1.3 +dependency_overrides: + watcher: ^1.1.0 + # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/cw_core/pubspec.yaml b/cw_core/pubspec.yaml index 04a840d4e..51d671dc7 100644 --- a/cw_core/pubspec.yaml +++ b/cw_core/pubspec.yaml @@ -28,11 +28,14 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - build_runner: ^2.1.11 + build_runner: ^2.4.7 build_resolvers: ^2.0.9 mobx_codegen: ^2.0.7 hive_generator: ^2.0.1 +dependency_overrides: + watcher: ^1.1.0 + # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/cw_ethereum/pubspec.yaml b/cw_ethereum/pubspec.yaml index 649ec574b..cbe6644a4 100644 --- a/cw_ethereum/pubspec.yaml +++ b/cw_ethereum/pubspec.yaml @@ -22,7 +22,11 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - build_runner: ^2.1.11 + build_runner: ^2.4.7 + +dependency_overrides: + watcher: ^1.1.0 + flutter: # assets: # - images/a_dot_burr.jpeg diff --git a/cw_evm/pubspec.yaml b/cw_evm/pubspec.yaml index c202cc72a..eaafb8415 100644 --- a/cw_evm/pubspec.yaml +++ b/cw_evm/pubspec.yaml @@ -27,11 +27,14 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - build_runner: ^2.1.11 + build_runner: ^2.4.7 mobx_codegen: ^2.0.7 hive_generator: ^1.1.3 flutter_lints: ^2.0.0 +dependency_overrides: + watcher: ^1.1.0 + flutter: # assets: # - images/a_dot_burr.jpeg diff --git a/cw_haven/pubspec.yaml b/cw_haven/pubspec.yaml index c215ab779..d868c986d 100644 --- a/cw_haven/pubspec.yaml +++ b/cw_haven/pubspec.yaml @@ -24,11 +24,14 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - build_runner: ^2.1.11 + build_runner: ^2.4.7 mobx_codegen: ^2.0.7 build_resolvers: ^2.0.9 hive_generator: ^1.1.3 +dependency_overrides: + watcher: ^1.1.0 + # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/cw_monero/pubspec.yaml b/cw_monero/pubspec.yaml index a6fe7f967..c49a541ab 100644 --- a/cw_monero/pubspec.yaml +++ b/cw_monero/pubspec.yaml @@ -26,11 +26,14 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - build_runner: ^2.1.11 + build_runner: ^2.4.7 build_resolvers: ^2.0.9 mobx_codegen: ^2.0.7 hive_generator: ^1.1.3 +dependency_overrides: + watcher: ^1.1.0 + # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/cw_nano/pubspec.yaml b/cw_nano/pubspec.yaml index a4b8732fd..768c1bb4e 100644 --- a/cw_nano/pubspec.yaml +++ b/cw_nano/pubspec.yaml @@ -32,10 +32,13 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - build_runner: ^2.1.11 + build_runner: ^2.4.7 mobx_codegen: ^2.0.7 hive_generator: ^1.1.3 +dependency_overrides: + watcher: ^1.1.0 + # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/cw_polygon/pubspec.yaml b/cw_polygon/pubspec.yaml index 505838d7c..61a474002 100644 --- a/cw_polygon/pubspec.yaml +++ b/cw_polygon/pubspec.yaml @@ -28,7 +28,10 @@ dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^2.0.0 - build_runner: ^2.1.11 + build_runner: ^2.4.7 + +dependency_overrides: + watcher: ^1.1.0 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/cw_solana/pubspec.yaml b/cw_solana/pubspec.yaml index 7e24983bf..6b59282b4 100644 --- a/cw_solana/pubspec.yaml +++ b/cw_solana/pubspec.yaml @@ -26,10 +26,13 @@ dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^2.0.0 - build_runner: ^2.1.11 + build_runner: ^2.4.7 mobx_codegen: ^2.0.7 hive_generator: ^1.1.3 +dependency_overrides: + watcher: ^1.1.0 + flutter: # assets: # - images/a_dot_burr.jpeg diff --git a/lib/entities/biometric_auth.dart b/lib/entities/biometric_auth.dart index febbfa469..463a22775 100644 --- a/lib/entities/biometric_auth.dart +++ b/lib/entities/biometric_auth.dart @@ -1,32 +1,28 @@ -import 'package:local_auth/local_auth.dart'; import 'package:flutter/services.dart'; -import 'package:cake_wallet/generated/i18n.dart'; +import 'package:flutter_local_authentication/flutter_local_authentication.dart'; class BiometricAuth { - final _localAuth = LocalAuthentication(); + final _flutterLocalAuthenticationPlugin = FlutterLocalAuthentication(); Future isAuthenticated() async { try { - return await _localAuth.authenticate( - localizedReason: S.current.biometric_auth_reason, - options: AuthenticationOptions( - biometricOnly: true, - useErrorDialogs: true, - stickyAuth: false)); - } on PlatformException catch (e) { + final authenticated = await _flutterLocalAuthenticationPlugin.authenticate(); + return authenticated; + } catch (e) { print(e); } - return false; } Future canCheckBiometrics() async { + bool canAuthenticate; try { - return await _localAuth.canCheckBiometrics; - } on PlatformException catch (e) { - print(e); + canAuthenticate = await _flutterLocalAuthenticationPlugin.canAuthenticate(); + } catch (error) { + print("Exception checking support. $error"); + canAuthenticate = false; } - return false; + return canAuthenticate; } } diff --git a/lib/locales/hausa_intl.dart b/lib/locales/hausa_intl.dart index 749d39a4d..6cf757b60 100644 --- a/lib/locales/hausa_intl.dart +++ b/lib/locales/hausa_intl.dart @@ -751,6 +751,50 @@ class HaMaterialLocalizations extends GlobalMaterialLocalizations { @override String get scrimOnTapHintRaw => "Scrip on Tap"; + + @override + // TODO: implement collapsedHint + String get collapsedHint => "collapsedHint"; + + @override + // TODO: implement expandedHint + String get expandedHint => "expandedHint"; + + @override + // TODO: implement expansionTileCollapsedHint + String get expansionTileCollapsedHint => "expansionTileCollapsedHint"; + + @override + // TODO: implement expansionTileCollapsedTapHint + String get expansionTileCollapsedTapHint => "expansionTileCollapsedTapHint"; + + @override + // TODO: implement expansionTileExpandedHint + String get expansionTileExpandedHint => "expansionTileExpandedHint"; + + @override + // TODO: implement expansionTileExpandedTapHint + String get expansionTileExpandedTapHint => "expansionTileExpandedTapHint"; + + @override + // TODO: implement scanTextButtonLabel + String get scanTextButtonLabel => "scanTextButtonLabel"; + + @override + // TODO: implement lookUpButtonLabel + String get lookUpButtonLabel => "lookUpButtonLabel"; + + @override + // TODO: implement menuDismissLabel + String get menuDismissLabel => "menuDismissLabel"; + + @override + // TODO: implement searchWebButtonLabel + String get searchWebButtonLabel => "searchWebButtonLabel"; + + @override + // TODO: implement shareButtonLabel + String get shareButtonLabel => "shareButtonLabel"; } /// Cupertino Support @@ -955,4 +999,24 @@ class HaCupertinoLocalizations extends GlobalCupertinoLocalizations { @override String get noSpellCheckReplacementsLabel => ""; + + @override + // TODO: implement clearButtonLabel + String get clearButtonLabel => "clearButtonLabel"; + + @override + // TODO: implement lookUpButtonLabel + String get lookUpButtonLabel => "lookUpButtonLabel"; + + @override + // TODO: implement menuDismissLabel + String get menuDismissLabel => "menuDismissLabel"; + + @override + // TODO: implement searchWebButtonLabel + String get searchWebButtonLabel => "searchWebButtonLabel"; + + @override + // TODO: implement shareButtonLabel + String get shareButtonLabel => "shareButtonLabel"; } diff --git a/lib/locales/yoruba_intl.dart b/lib/locales/yoruba_intl.dart index 889c21cb7..3c720b80e 100644 --- a/lib/locales/yoruba_intl.dart +++ b/lib/locales/yoruba_intl.dart @@ -1,4 +1,3 @@ - import 'dart:async'; import 'package:flutter/cupertino.dart'; @@ -164,62 +163,62 @@ const yoDateSymbols = { 'ọjọ́ Àbámẹ́ta', ], 'STANDALONEWEEKDAYS': [ -'Ọjọ́ Ajé', -'Ọjọ́ Ìsẹ́gun', -'Ọjọ́ Ìsẹ́gun-Ẹtì', -'Ọjọ́ Ìsẹ́gun-Ọ̀rú', -'Ọjọ́ Àìkú', -'Ọjọ́ Jímọ̀', -'Ọjọ́ Àbámẹ́ta', -], -'SHORTWEEKDAYS': [ -'Ajé', -'Ìsẹ́gun', -'Ìsẹ́gun-Ẹtì', -'Ìsẹ́gun-Ọ̀rú', -'Àìkú', -'Jímọ̀', -'Àbámẹ́ta', -], -'STANDALONESHORTWEEKDAYS': [ -'Ajé', -'Ìsẹ́gun', -'Ìsẹ́gun-Ẹtì', -'Ìsẹ́gun-Ọ̀rú', -'Àìkú', -'Jímọ̀', -'Àbámẹ́ta', -], -'NARROWWEEKDAYS': [ -'A', -'A', -'Ì', -'A', -'À', -'J', -'À', -], -'STANDALONENARROWWEEKDAYS': [ -'A', -'A', -'Ì', -'A', -'À', -'J', -'À', -], -'SHORTQUARTERS': [ -'K1', -'K2', -'K3', -'K4', -], -'QUARTERS': [ -'1. kwata', -'2. kwata', -'3. kwata', -'4. kwata', -], + 'Ọjọ́ Ajé', + 'Ọjọ́ Ìsẹ́gun', + 'Ọjọ́ Ìsẹ́gun-Ẹtì', + 'Ọjọ́ Ìsẹ́gun-Ọ̀rú', + 'Ọjọ́ Àìkú', + 'Ọjọ́ Jímọ̀', + 'Ọjọ́ Àbámẹ́ta', + ], + 'SHORTWEEKDAYS': [ + 'Ajé', + 'Ìsẹ́gun', + 'Ìsẹ́gun-Ẹtì', + 'Ìsẹ́gun-Ọ̀rú', + 'Àìkú', + 'Jímọ̀', + 'Àbámẹ́ta', + ], + 'STANDALONESHORTWEEKDAYS': [ + 'Ajé', + 'Ìsẹ́gun', + 'Ìsẹ́gun-Ẹtì', + 'Ìsẹ́gun-Ọ̀rú', + 'Àìkú', + 'Jímọ̀', + 'Àbámẹ́ta', + ], + 'NARROWWEEKDAYS': [ + 'A', + 'A', + 'Ì', + 'A', + 'À', + 'J', + 'À', + ], + 'STANDALONENARROWWEEKDAYS': [ + 'A', + 'A', + 'Ì', + 'A', + 'À', + 'J', + 'À', + ], + 'SHORTQUARTERS': [ + 'K1', + 'K2', + 'K3', + 'K4', + ], + 'QUARTERS': [ + '1. kwata', + '2. kwata', + '3. kwata', + '4. kwata', + ], 'AMPMS': [ 'a.m.', 'p.m.', @@ -316,339 +315,339 @@ class YoMaterialLocalizations extends GlobalMaterialLocalizations { }); // #docregion Getters -@override -String get moreButtonTooltip => r'Kò sí ìròhùn tí ó múni'; + @override + String get moreButtonTooltip => r'Kò sí ìròhùn tí ó múni'; -@override -String get aboutListTileTitleRaw => r'Fun Àpótí àwọn $applicationname'; + @override + String get aboutListTileTitleRaw => r'Fun Àpótí àwọn $applicationname'; -@override -String get alertDialogLabel => r'Ìròhùn Àlàyé'; + @override + String get alertDialogLabel => r'Ìròhùn Àlàyé'; // #enddocregion Getters -@override -String get anteMeridiemAbbreviation => r'AM'; + @override + String get anteMeridiemAbbreviation => r'AM'; -@override -String get backButtonTooltip => r'Fíran'; + @override + String get backButtonTooltip => r'Fíran'; -@override -String get cancelButtonLabel => r'FAGILE'; + @override + String get cancelButtonLabel => r'FAGILE'; -@override -String get closeButtonLabel => r'KÚ'; + @override + String get closeButtonLabel => r'KÚ'; -@override -String get closeButtonTooltip => r'Kú'; + @override + String get closeButtonTooltip => r'Kú'; -@override -String get collapsedIconTapHint => r'Tá'; + @override + String get collapsedIconTapHint => r'Tá'; -@override -String get continueButtonLabel => r'TÓ WÁ'; + @override + String get continueButtonLabel => r'TÓ WÁ'; -@override -String get copyButtonLabel => r'DÚPLÍKÉTÍ'; + @override + String get copyButtonLabel => r'DÚPLÍKÉTÍ'; -@override -String get cutButtonLabel => r'TÒ'; + @override + String get cutButtonLabel => r'TÒ'; -@override -String get deleteButtonTooltip => r'Máa kú'; + @override + String get deleteButtonTooltip => r'Máa kú'; -@override -String get dialogLabel => r'Ìròhùn'; + @override + String get dialogLabel => r'Ìròhùn'; -@override -String get drawerLabel => r'Àgbèjọ àwọn àpọ̀tí'; + @override + String get drawerLabel => r'Àgbèjọ àwọn àpọ̀tí'; -@override -String get expandedIconTapHint => r'Tá'; + @override + String get expandedIconTapHint => r'Tá'; -@override -String get firstPageTooltip => r'Ojú ewe'; + @override + String get firstPageTooltip => r'Ojú ewe'; -@override -String get hideAccountsLabel => r'Fí èrò àpótí wáyé sílẹ̀'; + @override + String get hideAccountsLabel => r'Fí èrò àpótí wáyé sílẹ̀'; -@override -String get lastPageTooltip => r'Ojú ayé'; + @override + String get lastPageTooltip => r'Ojú ayé'; -@override -String get licensesPageTitle => r'Ìròhùn Ọdún'; + @override + String get licensesPageTitle => r'Ìròhùn Ọdún'; -@override -String get modalBarrierDismissLabel => r'Sọ'; + @override + String get modalBarrierDismissLabel => r'Sọ'; -@override -String get nextMonthTooltip => r'Oṣù kọja'; + @override + String get nextMonthTooltip => r'Oṣù kọja'; -@override -String get nextPageTooltip => r'Ojú ọjọ́ kẹta'; + @override + String get nextPageTooltip => r'Ojú ọjọ́ kẹta'; -@override -String get okButtonLabel => r'Ò daájú'; -@override + @override + String get okButtonLabel => r'Ò daájú'; + @override // A custom drawer tooltip message. -String get openAppDrawerTooltip => r'Aya ntọju Iwe Awọn Aka'; + String get openAppDrawerTooltip => r'Aya ntọju Iwe Awọn Aka'; // #docregion Raw -@override -String get pageRowsInfoTitleRaw => r'$firstRow–$lastRow lati $rowCount'; + @override + String get pageRowsInfoTitleRaw => r'$firstRow–$lastRow lati $rowCount'; -@override -String get pageRowsInfoTitleApproximateRaw => r'$firstRow–$lastRow lati kiakia $rowCount'; + @override + String get pageRowsInfoTitleApproximateRaw => r'$firstRow–$lastRow lati kiakia $rowCount'; // #enddocregion Raw -@override -String get pasteButtonLabel => r'TÌ'; - -@override -String get popupMenuLabel => r'Meniu Pop-up'; - -@override -String get menuBarMenuLabel => r'Meniu Akọkọ'; - -@override -String get postMeridiemAbbreviation => r'PM'; - -@override -String get previousMonthTooltip => r'Oṣu Kanakana'; - -@override -String get previousPageTooltip => r'Ojú ewé akọkọ kan'; - -@override -String get refreshIndicatorSemanticLabel => r'Gbiyanju'; - -@override -String? get remainingTextFieldCharacterCountFew => null; - -@override -String? get remainingTextFieldCharacterCountMany => null; - -@override -String get remainingTextFieldCharacterCountOne => r'1 àmì báálẹ̀'; - -@override -String get remainingTextFieldCharacterCountOther => r'$remainingCount àmì báálẹ̀'; - -@override -String? get remainingTextFieldCharacterCountTwo => null; - -@override -String get remainingTextFieldCharacterCountZero => r'Kò sí ìwọlé létà láti ń ṣe'; - -@override -String get reorderItemDown => r'Jù sí ilẹ'; - -@override -String get reorderItemLeft => r'Jù sí àrà'; - -@override -String get reorderItemRight => r'Jù sí òtútù'; - -@override -String get reorderItemToEnd => r'Jù sí ìbẹ̀jì'; - -@override -String get reorderItemToStart => r'Jù sí àkọ́kọ́'; - -@override -String get reorderItemUp => r'Jù sí ọ̀rùn'; - -@override -String get rowsPerPageTitle => r'Ìlò Fún àwọn Ìtọ́kasíwájú:'; - -@override -ScriptCategory get scriptCategory => ScriptCategory.englishLike; - -@override -String get searchFieldLabel => 'Ṣẹda'; - -@override -String get selectAllButtonLabel => 'FADỌHỌN DỌFÚN GBÁJÚMỌ̀'; - -@override -String? get selectedRowCountTitleFew => null; - -@override -String? get selectedRowCountTitleMany => null; - -@override -String get selectedRowCountTitleOne => '1 káyé'; - -@override -String get selectedRowCountTitleOther => r'$selectedRowCount káyé'; - -@override -String? get selectedRowCountTitleTwo => null; - -@override -String get selectedRowCountTitleZero => 'Kò sí káyé ti o wọlé'; - -@override -String get showAccountsLabel => 'Fi iyipada mu kọ'; - -@override -String get showMenuTooltip => 'Fi Meniu mu kọ'; - -@override -String get signedInLabel => 'Ọ̀nà'; - -@override -String get tabLabelRaw => r'Àwọn tabin $tabIndex lati $tabCount'; - @override -TimeOfDayFormat get timeOfDayFormatRaw => TimeOfDayFormat.h_colon_mm_space_a; - -@override -String get timePickerHourModeAnnouncement => 'Tuntun waqtu lọ'; - -@override -String get timePickerMinuteModeAnnouncement => 'Tuntun daɗi minti'; - -@override -String get viewLicensesButtonLabel => 'WO NIKI'; - -@override -List get narrowWeekdays => const ['L', 'L', 'A', 'O', 'Ọ', 'Ẹ', 'Ẹ']; - -@override -int get firstDayOfWeekIndex => 0; - -static const LocalizationsDelegate delegate = -_YoMaterialLocalizationsDelegate(); - -@override -String get calendarModeButtonLabel => 'Tọ́rọ̀ kálẹ̀ndà'; - -@override -String get dateHelpText => 'mm/dd/yyyy'; - -@override -String get dateInputLabel => 'Firanṣẹ̀ Ọjọ́'; - -@override -String get dateOutOfRangeLabel => 'Nínú iwọ̀ lọ́wọ́'; - -@override -String get datePickerHelpText => 'WÁSÍ'; - -@override -String get dateRangeEndDateSemanticLabelRaw => r'Ọjọ́ tuntun to ṣà'; - -@override -String get dateRangeEndLabel => 'Ọjọ́ tuntun to ṣà'; - -@override -String get dateRangePickerHelpText => 'WÁSÍ ÌGBÀ'; - -@override -String get dateRangeStartDateSemanticLabelRaw => 'Ọjọ́ tuntun ti dá'; - -@override -String get dateRangeStartLabel => 'Ọjọ́ tuntun ti dá'; - -@override -String get dateSeparator => '/'; - -@override -String get dialModeButtonLabel => 'Tọ́rọ̀ wakati'; - -@override -String get inputDateModeButtonLabel => 'Tọ́rọ̀ firanṣẹ̀ ọjọ́'; - -@override -String get inputTimeModeButtonLabel => 'Tọ́rọ̀ wakati bayi lọ́wọ́'; - -@override -String get invalidDateFormatLabel => 'Akọ́kọ́tọ́ tó jẹ́kúnrin'; - -@override -String get invalidDateRangeLabel => 'Àmì jẹ́ káàkiri lẹ́yìn ilé'; - -@override -String get invalidTimeLabel => 'Akọ́kọ́tọ́ àkójọ ìwádìí'; - -@override -String get licensesPackageDetailTextOther => r'$licenseCount àwọn níkí'; - -@override -String get saveButtonLabel => 'TÙN DÁRA'; - -@override -String get selectYearSemanticsLabel => 'Fọ́ọ̀ shẹ́kàrà'; - -@override -String get timePickerDialHelpText => 'WÁSÍ WÁKÀTÌ'; - -@override -String get timePickerHourLabel => 'Wákàtì àṣà'; - -@override -String get timePickerInputHelpText => 'Shìgárà wákàtì'; - -@override -String get timePickerMinuteLabel => 'Mìntì'; - -@override -String get unspecifiedDate => 'Ọjọ̀kúnrin'; - -@override -String get unspecifiedDateRange => 'Ọjọ̀kúnrin àdáyọ̀'; - -@override -String get keyboardKeyAlt => 'Alt'; - -@override -String get keyboardKeyAltGraph => 'AltGraph'; - -@override -String get keyboardKeyBackspace => 'Báckspàcè'; - -@override -String get keyboardKeyCapsLock => 'Caps Lock'; - -@override -String get keyboardKeyChannelDown => 'Báyàkàmmàlàsàké'; - -@override -String get keyboardKeyChannelUp => 'Yíkàmmàlàsàké'; - -@override -String get keyboardKeyControl => 'Kọ́ntírọ̀l'; - -@override -String get keyboardKeyDelete => 'Shápè'; - -@override -String get keyboardKeyEject => 'Èjẹ̀tì'; - -@override -String get keyboardKeyEnd => 'Tàbí'; - -@override -String get keyboardKeyEscape => 'Tòkè'; + String get pasteButtonLabel => r'TÌ'; @override -String get keyboardKeyFn => 'Fn'; + String get popupMenuLabel => r'Meniu Pop-up'; -@override -String get keyboardKeyHome => 'Ile'; + @override + String get menuBarMenuLabel => r'Meniu Akọkọ'; -@override -String get keyboardKeyInsert => 'Fi sori'; + @override + String get postMeridiemAbbreviation => r'PM'; -@override -String get keyboardKeyMeta => 'Meta'; + @override + String get previousMonthTooltip => r'Oṣu Kanakana'; -@override -String get keyboardKeyMetaMacOs => 'Amfani pẹlu Command'; + @override + String get previousPageTooltip => r'Ojú ewé akọkọ kan'; -@override -String get keyboardKeyMetaWindows => 'Windows'; + @override + String get refreshIndicatorSemanticLabel => r'Gbiyanju'; + + @override + String? get remainingTextFieldCharacterCountFew => null; + + @override + String? get remainingTextFieldCharacterCountMany => null; + + @override + String get remainingTextFieldCharacterCountOne => r'1 àmì báálẹ̀'; + + @override + String get remainingTextFieldCharacterCountOther => r'$remainingCount àmì báálẹ̀'; + + @override + String? get remainingTextFieldCharacterCountTwo => null; + + @override + String get remainingTextFieldCharacterCountZero => r'Kò sí ìwọlé létà láti ń ṣe'; + + @override + String get reorderItemDown => r'Jù sí ilẹ'; + + @override + String get reorderItemLeft => r'Jù sí àrà'; + + @override + String get reorderItemRight => r'Jù sí òtútù'; + + @override + String get reorderItemToEnd => r'Jù sí ìbẹ̀jì'; + + @override + String get reorderItemToStart => r'Jù sí àkọ́kọ́'; + + @override + String get reorderItemUp => r'Jù sí ọ̀rùn'; + + @override + String get rowsPerPageTitle => r'Ìlò Fún àwọn Ìtọ́kasíwájú:'; + + @override + ScriptCategory get scriptCategory => ScriptCategory.englishLike; + + @override + String get searchFieldLabel => 'Ṣẹda'; + + @override + String get selectAllButtonLabel => 'FADỌHỌN DỌFÚN GBÁJÚMỌ̀'; + + @override + String? get selectedRowCountTitleFew => null; + + @override + String? get selectedRowCountTitleMany => null; + + @override + String get selectedRowCountTitleOne => '1 káyé'; + + @override + String get selectedRowCountTitleOther => r'$selectedRowCount káyé'; + + @override + String? get selectedRowCountTitleTwo => null; + + @override + String get selectedRowCountTitleZero => 'Kò sí káyé ti o wọlé'; + + @override + String get showAccountsLabel => 'Fi iyipada mu kọ'; + + @override + String get showMenuTooltip => 'Fi Meniu mu kọ'; + + @override + String get signedInLabel => 'Ọ̀nà'; + + @override + String get tabLabelRaw => r'Àwọn tabin $tabIndex lati $tabCount'; + + @override + TimeOfDayFormat get timeOfDayFormatRaw => TimeOfDayFormat.h_colon_mm_space_a; + + @override + String get timePickerHourModeAnnouncement => 'Tuntun waqtu lọ'; + + @override + String get timePickerMinuteModeAnnouncement => 'Tuntun daɗi minti'; + + @override + String get viewLicensesButtonLabel => 'WO NIKI'; + + @override + List get narrowWeekdays => const ['L', 'L', 'A', 'O', 'Ọ', 'Ẹ', 'Ẹ']; + + @override + int get firstDayOfWeekIndex => 0; + + static const LocalizationsDelegate delegate = + _YoMaterialLocalizationsDelegate(); + + @override + String get calendarModeButtonLabel => 'Tọ́rọ̀ kálẹ̀ndà'; + + @override + String get dateHelpText => 'mm/dd/yyyy'; + + @override + String get dateInputLabel => 'Firanṣẹ̀ Ọjọ́'; + + @override + String get dateOutOfRangeLabel => 'Nínú iwọ̀ lọ́wọ́'; + + @override + String get datePickerHelpText => 'WÁSÍ'; + + @override + String get dateRangeEndDateSemanticLabelRaw => r'Ọjọ́ tuntun to ṣà'; + + @override + String get dateRangeEndLabel => 'Ọjọ́ tuntun to ṣà'; + + @override + String get dateRangePickerHelpText => 'WÁSÍ ÌGBÀ'; + + @override + String get dateRangeStartDateSemanticLabelRaw => 'Ọjọ́ tuntun ti dá'; + + @override + String get dateRangeStartLabel => 'Ọjọ́ tuntun ti dá'; + + @override + String get dateSeparator => '/'; + + @override + String get dialModeButtonLabel => 'Tọ́rọ̀ wakati'; + + @override + String get inputDateModeButtonLabel => 'Tọ́rọ̀ firanṣẹ̀ ọjọ́'; + + @override + String get inputTimeModeButtonLabel => 'Tọ́rọ̀ wakati bayi lọ́wọ́'; + + @override + String get invalidDateFormatLabel => 'Akọ́kọ́tọ́ tó jẹ́kúnrin'; + + @override + String get invalidDateRangeLabel => 'Àmì jẹ́ káàkiri lẹ́yìn ilé'; + + @override + String get invalidTimeLabel => 'Akọ́kọ́tọ́ àkójọ ìwádìí'; + + @override + String get licensesPackageDetailTextOther => r'$licenseCount àwọn níkí'; + + @override + String get saveButtonLabel => 'TÙN DÁRA'; + + @override + String get selectYearSemanticsLabel => 'Fọ́ọ̀ shẹ́kàrà'; + + @override + String get timePickerDialHelpText => 'WÁSÍ WÁKÀTÌ'; + + @override + String get timePickerHourLabel => 'Wákàtì àṣà'; + + @override + String get timePickerInputHelpText => 'Shìgárà wákàtì'; + + @override + String get timePickerMinuteLabel => 'Mìntì'; + + @override + String get unspecifiedDate => 'Ọjọ̀kúnrin'; + + @override + String get unspecifiedDateRange => 'Ọjọ̀kúnrin àdáyọ̀'; + + @override + String get keyboardKeyAlt => 'Alt'; + + @override + String get keyboardKeyAltGraph => 'AltGraph'; + + @override + String get keyboardKeyBackspace => 'Báckspàcè'; + + @override + String get keyboardKeyCapsLock => 'Caps Lock'; + + @override + String get keyboardKeyChannelDown => 'Báyàkàmmàlàsàké'; + + @override + String get keyboardKeyChannelUp => 'Yíkàmmàlàsàké'; + + @override + String get keyboardKeyControl => 'Kọ́ntírọ̀l'; + + @override + String get keyboardKeyDelete => 'Shápè'; + + @override + String get keyboardKeyEject => 'Èjẹ̀tì'; + + @override + String get keyboardKeyEnd => 'Tàbí'; + + @override + String get keyboardKeyEscape => 'Tòkè'; + + @override + String get keyboardKeyFn => 'Fn'; + + @override + String get keyboardKeyHome => 'Ile'; + + @override + String get keyboardKeyInsert => 'Fi sori'; + + @override + String get keyboardKeyMeta => 'Meta'; + + @override + String get keyboardKeyMetaMacOs => 'Amfani pẹlu Command'; + + @override + String get keyboardKeyMetaWindows => 'Windows'; @override String get keyboardKeyNumLock => 'Num Lock'; @@ -751,6 +750,50 @@ String get keyboardKeyMetaWindows => 'Windows'; @override String get scrimOnTapHintRaw => "Scrip on Tap"; + + @override + // TODO: implement collapsedHint + String get collapsedHint => "collapsedHint"; + + @override + // TODO: implement expandedHint + String get expandedHint => "expandedHint"; + + @override + // TODO: implement expansionTileCollapsedHint + String get expansionTileCollapsedHint => "expansionTileCollapsedHint"; + + @override + // TODO: implement expansionTileCollapsedTapHint + String get expansionTileCollapsedTapHint => "expansionTileCollapsedTapHint"; + + @override + // TODO: implement expansionTileExpandedHint + String get expansionTileExpandedHint => "expansionTileExpandedHint"; + + @override + // TODO: implement expansionTileExpandedTapHint + String get expansionTileExpandedTapHint => "expansionTileExpandedTapHint"; + + @override + // TODO: implement scanTextButtonLabel + String get scanTextButtonLabel => "scanTextButtonLabel"; + + @override + // TODO: implement lookUpButtonLabel + String get lookUpButtonLabel => "lookUpButtonLabel"; + + @override + // TODO: implement menuDismissLabel + String get menuDismissLabel => "menuDismissLabel"; + + @override + // TODO: implement searchWebButtonLabel + String get searchWebButtonLabel => "searchWebButtonLabel"; + + @override + // TODO: implement shareButtonLabel + String get shareButtonLabel => "shareButtonLabel"; } /// Cupertino Support @@ -821,138 +864,158 @@ class YoCupertinoLocalizations extends GlobalCupertinoLocalizations { required super.singleDigitSecondFormat, }); -@override -String get alertDialogLabel => 'Àdàkárò'; + @override + String get alertDialogLabel => 'Àdàkárò'; -@override -String get anteMeridiemAbbreviation => 'AM'; + @override + String get anteMeridiemAbbreviation => 'AM'; -@override -String get copyButtonLabel => 'Kòpy'; + @override + String get copyButtonLabel => 'Kòpy'; -@override -String get cutButtonLabel => 'Kọ́t'; + @override + String get cutButtonLabel => 'Kọ́t'; -@override -String get datePickerDateOrderString => 'mdy'; + @override + String get datePickerDateOrderString => 'mdy'; -@override -String get datePickerDateTimeOrderString => 'date_time_dayPeriod'; + @override + String get datePickerDateTimeOrderString => 'date_time_dayPeriod'; -@override -String? get datePickerHourSemanticsLabelFew => null; + @override + String? get datePickerHourSemanticsLabelFew => null; -@override -String? get datePickerHourSemanticsLabelMany => null; + @override + String? get datePickerHourSemanticsLabelMany => null; -@override -String? get datePickerHourSemanticsLabelOne => r"$hour o'clock"; + @override + String? get datePickerHourSemanticsLabelOne => r"$hour o'clock"; -@override -String get datePickerHourSemanticsLabelOther => r"$hour o'clock"; + @override + String get datePickerHourSemanticsLabelOther => r"$hour o'clock"; -@override -String? get datePickerHourSemanticsLabelTwo => null; + @override + String? get datePickerHourSemanticsLabelTwo => null; -@override -String? get datePickerHourSemanticsLabelZero => null; + @override + String? get datePickerHourSemanticsLabelZero => null; -@override -String? get datePickerMinuteSemanticsLabelFew => null; + @override + String? get datePickerMinuteSemanticsLabelFew => null; -@override -String? get datePickerMinuteSemanticsLabelMany => null; + @override + String? get datePickerMinuteSemanticsLabelMany => null; -@override -String? get datePickerMinuteSemanticsLabelOne => '1 wakati'; + @override + String? get datePickerMinuteSemanticsLabelOne => '1 wakati'; -@override -String get datePickerMinuteSemanticsLabelOther => r'$minute wakati'; + @override + String get datePickerMinuteSemanticsLabelOther => r'$minute wakati'; -@override -String? get datePickerMinuteSemanticsLabelTwo => null; + @override + String? get datePickerMinuteSemanticsLabelTwo => null; -@override -String? get datePickerMinuteSemanticsLabelZero => null; + @override + String? get datePickerMinuteSemanticsLabelZero => null; -@override -String get modalBarrierDismissLabel => 'Búta'; + @override + String get modalBarrierDismissLabel => 'Búta'; -@override -String get pasteButtonLabel => 'Tẹ́ẹ́'; + @override + String get pasteButtonLabel => 'Tẹ́ẹ́'; -@override -String get postMeridiemAbbreviation => 'PM'; + @override + String get postMeridiemAbbreviation => 'PM'; -@override -String get searchTextFieldPlaceholderLabel => 'Wúró àtúntà'; + @override + String get searchTextFieldPlaceholderLabel => 'Wúró àtúntà'; -@override -String get selectAllButtonLabel => 'Fírànsé gbógbo'; + @override + String get selectAllButtonLabel => 'Fírànsé gbógbo'; -@override -String get tabSemanticsLabelRaw => r'Tab $tabIndex nínú $tabCount'; + @override + String get tabSemanticsLabelRaw => r'Tab $tabIndex nínú $tabCount'; -@override -String? get timerPickerHourLabelFew => null; + @override + String? get timerPickerHourLabelFew => null; -@override -String? get timerPickerHourLabelMany => null; + @override + String? get timerPickerHourLabelMany => null; -@override -String? get timerPickerHourLabelOne => 'òǹdì'; + @override + String? get timerPickerHourLabelOne => 'òǹdì'; -@override -String get timerPickerHourLabelOther => 'òǹdì'; + @override + String get timerPickerHourLabelOther => 'òǹdì'; -@override -String? get timerPickerHourLabelTwo => null; + @override + String? get timerPickerHourLabelTwo => null; -@override -String? get timerPickerHourLabelZero => null; + @override + String? get timerPickerHourLabelZero => null; -@override -String? get timerPickerMinuteLabelFew => null; + @override + String? get timerPickerMinuteLabelFew => null; -@override -String? get timerPickerMinuteLabelMany => null; + @override + String? get timerPickerMinuteLabelMany => null; -@override -String? get timerPickerMinuteLabelOne => 'wakati.'; + @override + String? get timerPickerMinuteLabelOne => 'wakati.'; -@override -String get timerPickerMinuteLabelOther => 'wakati.'; + @override + String get timerPickerMinuteLabelOther => 'wakati.'; -@override -String? get timerPickerMinuteLabelTwo => null; + @override + String? get timerPickerMinuteLabelTwo => null; -@override -String? get timerPickerMinuteLabelZero => null; + @override + String? get timerPickerMinuteLabelZero => null; -@override -String? get timerPickerSecondLabelFew => null; + @override + String? get timerPickerSecondLabelFew => null; -@override -String? get timerPickerSecondLabelMany => null; + @override + String? get timerPickerSecondLabelMany => null; -@override -String? get timerPickerSecondLabelOne => 'dákìkà.'; + @override + String? get timerPickerSecondLabelOne => 'dákìkà.'; -@override -String get timerPickerSecondLabelOther => 'dákìkà.'; + @override + String get timerPickerSecondLabelOther => 'dákìkà.'; -@override -String? get timerPickerSecondLabelTwo => null; + @override + String? get timerPickerSecondLabelTwo => null; -@override -String? get timerPickerSecondLabelZero => null; + @override + String? get timerPickerSecondLabelZero => null; -@override -String get todayLabel => 'Oyọ'; + @override + String get todayLabel => 'Oyọ'; static const LocalizationsDelegate delegate = _YoCupertinoLocalizationsDelegate(); @override String get noSpellCheckReplacementsLabel => ""; + + @override + // TODO: implement clearButtonLabel + String get clearButtonLabel => "clearButtonLabel"; + + @override + // TODO: implement lookUpButtonLabel + String get lookUpButtonLabel => "lookUpButtonLabel"; + + @override + // TODO: implement menuDismissLabel + String get menuDismissLabel => "menuDismissLabel"; + + @override + // TODO: implement searchWebButtonLabel + String get searchWebButtonLabel => "searchWebButtonLabel"; + + @override + // TODO: implement shareButtonLabel + String get shareButtonLabel => "shareButtonLabel"; } diff --git a/lib/src/screens/settings/security_backup_page.dart b/lib/src/screens/settings/security_backup_page.dart index e559e9b15..1f0f58ad4 100644 --- a/lib/src/screens/settings/security_backup_page.dart +++ b/lib/src/screens/settings/security_backup_page.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:cake_wallet/core/auth_service.dart'; import 'package:cake_wallet/entities/pin_code_required_duration.dart'; import 'package:cake_wallet/routes.dart'; @@ -58,7 +60,7 @@ class SecurityBackupPage extends BasePage { .shouldRequireTOTP2FAForAllSecurityAndBackupSettings, ), ), - if (DeviceInfo.instance.isMobile) + if (DeviceInfo.instance.isMobile || Platform.isMacOS || Platform.isLinux) Observer(builder: (_) { return SettingsSwitcherCell( title: S.current.settings_allow_biometrical_authentication, diff --git a/lib/src/screens/settings/tor_page.dart b/lib/src/screens/settings/tor_page.dart index ae1ef1677..2f544be35 100644 --- a/lib/src/screens/settings/tor_page.dart +++ b/lib/src/screens/settings/tor_page.dart @@ -146,7 +146,7 @@ class ConnectScreen extends StatelessWidget { ElevatedButton( onPressed: connect, style: ElevatedButton.styleFrom( - primary: Colors.blue, + // primary: Colors.blue, padding: EdgeInsets.symmetric(horizontal: 40, vertical: 15), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(30), @@ -211,7 +211,7 @@ class DisconnectScreen extends StatelessWidget { ElevatedButton( onPressed: disconnect, style: ElevatedButton.styleFrom( - primary: Colors.red, + // primary: Colors.red, padding: EdgeInsets.symmetric(horizontal: 40, vertical: 15), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(30), diff --git a/lib/src/widgets/validable_annotated_editable_text.dart b/lib/src/widgets/validable_annotated_editable_text.dart index 6c3fc4f16..7ea928d8a 100644 --- a/lib/src/widgets/validable_annotated_editable_text.dart +++ b/lib/src/widgets/validable_annotated_editable_text.dart @@ -1,8 +1,14 @@ -import 'package:cake_wallet/core/seed_validator.dart'; -import 'package:cw_core/wallet_type.dart'; import 'package:flutter/material.dart'; -class Annotation extends Comparable { + +extension Compare on Comparable { + bool operator <=(T other) => compareTo(other) <= 0; + bool operator >=(T other) => compareTo(other) >= 0; + bool operator <(T other) => compareTo(other) < 0; + bool operator >(T other) => compareTo(other) > 0; +} + +class Annotation implements Comparable { Annotation({required this.range, required this.style}); final TextRange range; @@ -12,7 +18,7 @@ class Annotation extends Comparable { int compareTo(Annotation other) => range.start.compareTo(other.range.start); } -class TextAnnotation extends Comparable { +class TextAnnotation implements Comparable { TextAnnotation({required this.text, required this.style}); final TextStyle style; diff --git a/lib/view_model/auth_view_model.dart b/lib/view_model/auth_view_model.dart index e50f4db0c..0e6590845 100644 --- a/lib/view_model/auth_view_model.dart +++ b/lib/view_model/auth_view_model.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'package:flutter/material.dart'; +import 'package:flutter_local_authentication/flutter_local_authentication.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:mobx/mobx.dart'; import 'package:cake_wallet/view_model/auth_state.dart'; @@ -105,16 +106,14 @@ abstract class AuthViewModelBase with Store { @action Future biometricAuth() async { + final _flutterLocalAuthenticationPlugin = FlutterLocalAuthentication(); + try { - final canBiometricAuth = await _biometricAuth.canCheckBiometrics(); - - if (canBiometricAuth) { - final isAuthenticated = await _biometricAuth.isAuthenticated(); - - if (isAuthenticated) { - state = ExecutedSuccessfullyState(); - } + final authenticated = await _flutterLocalAuthenticationPlugin.authenticate(); + if (!authenticated) { + throw Exception('Biometric authentication failed'); } + state = ExecutedSuccessfullyState(); } catch (e) { state = FailureState(e.toString()); } diff --git a/pubspec_base.yaml b/pubspec_base.yaml index 3ec3e7978..e1022864c 100644 --- a/pubspec_base.yaml +++ b/pubspec_base.yaml @@ -33,8 +33,8 @@ dependencies: dio: ^4.0.6 hive: ^2.2.3 hive_flutter: ^1.1.0 - local_auth: ^2.1.0 local_auth_android: 1.0.21 + flutter_local_authentication: ^1.2.0 package_info: ^2.0.0 #package_info_plus: ^1.4.2 devicelocale: diff --git a/pubspec_description.yaml b/pubspec_description.yaml index ebb6bf001..b51fe96d6 100644 --- a/pubspec_description.yaml +++ b/pubspec_description.yaml @@ -4,4 +4,4 @@ version: 0.0.0 publish_to: none environment: - sdk: ">=2.17.5 <3.0.0" \ No newline at end of file + sdk: ">=3.1.0 <4.0.0" \ No newline at end of file From e48962361a71888cb1c25d75204359ab2a660686 Mon Sep 17 00:00:00 2001 From: Matthew Fosse Date: Thu, 18 Apr 2024 11:10:32 -0700 Subject: [PATCH 02/17] script updates and new run-android script (#1396) --- configure_cake_wallet.sh | 12 +----------- run-android.sh | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 11 deletions(-) create mode 100755 run-android.sh diff --git a/configure_cake_wallet.sh b/configure_cake_wallet.sh index cc55e8fcc..837a002e9 100755 --- a/configure_cake_wallet.sh +++ b/configure_cake_wallet.sh @@ -23,14 +23,4 @@ source ./app_env.sh cakewallet ./app_config.sh cd ../.. && flutter pub get flutter packages pub run tool/generate_localization.dart -cd cw_core && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd .. -cd cw_evm && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd .. -cd cw_monero && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd .. -cd cw_bitcoin && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd .. -cd cw_haven && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd .. -cd cw_nano && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd .. -cd cw_bitcoin_cash && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd .. -cd cw_solana && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd .. -cd cw_ethereum && flutter pub get && cd .. -cd cw_polygon && flutter pub get && cd .. -flutter packages pub run build_runner build --delete-conflicting-outputs +./model_generator.sh diff --git a/run-android.sh b/run-android.sh new file mode 100755 index 000000000..dd694267a --- /dev/null +++ b/run-android.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# Get the current git branch +get_current_branch() { + if git rev-parse --git-dir > /dev/null 2>&1; then + branch=$(git rev-parse --abbrev-ref HEAD) + echo "$branch" + else + echo "Error: Not a git repository." + return 1 + fi +} + +# Update the app.properties file +update_app_properties() { + local branch=$1 + local file_path="./android/app.properties" + + sed -i "s/^id=.*/id=com.cakewallet.$branch/" "$file_path" + sed -i "s/^name=.*/name=$branch-Cake Wallet/" "$file_path" +} + +# only update app.properties if getting the current branch was successful +current_branch=$(get_current_branch) +if [[ $? -eq 0 ]]; then + update_app_properties "$current_branch" +fi + +# run the app +flutter run \ No newline at end of file From 4ed4659f9edfe60cbf063b6c10d0a1dc304d81e8 Mon Sep 17 00:00:00 2001 From: Omar Hatem Date: Thu, 18 Apr 2024 20:10:58 +0200 Subject: [PATCH 03/17] Revert "version bump to 3.13.9, auth working on mac (#1367)" (#1397) This reverts commit e6b4b08c24c1c2fb6987dcca233a3fee67c50d25. --- .github/workflows/pr_test_build.yml | 2 +- android/build.gradle | 2 +- cw_bitcoin/pubspec.yaml | 5 +- cw_bitcoin_cash/pubspec.yaml | 5 +- cw_core/pubspec.yaml | 5 +- cw_ethereum/pubspec.yaml | 6 +- cw_evm/pubspec.yaml | 5 +- cw_haven/pubspec.yaml | 5 +- cw_monero/pubspec.yaml | 5 +- cw_nano/pubspec.yaml | 5 +- cw_polygon/pubspec.yaml | 5 +- cw_solana/pubspec.yaml | 5 +- lib/entities/biometric_auth.dart | 26 +- lib/locales/hausa_intl.dart | 64 -- lib/locales/yoruba_intl.dart | 787 ++++++++---------- .../settings/security_backup_page.dart | 4 +- lib/src/screens/settings/tor_page.dart | 4 +- .../validable_annotated_editable_text.dart | 14 +- lib/view_model/auth_view_model.dart | 15 +- pubspec_base.yaml | 2 +- pubspec_description.yaml | 2 +- 21 files changed, 406 insertions(+), 567 deletions(-) diff --git a/.github/workflows/pr_test_build.yml b/.github/workflows/pr_test_build.yml index bfa378342..dc231df42 100644 --- a/.github/workflows/pr_test_build.yml +++ b/.github/workflows/pr_test_build.yml @@ -42,7 +42,7 @@ jobs: - name: Flutter action uses: subosito/flutter-action@v1 with: - flutter-version: "3.13.9" + flutter-version: "3.10.x" channel: stable - name: Install package dependencies diff --git a/android/build.gradle b/android/build.gradle index e182e39af..8286d9cb9 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '1.8.10' + ext.kotlin_version = '1.7.10' repositories { google() jcenter() diff --git a/cw_bitcoin/pubspec.yaml b/cw_bitcoin/pubspec.yaml index 1ccdb70c9..632a3140a 100644 --- a/cw_bitcoin/pubspec.yaml +++ b/cw_bitcoin/pubspec.yaml @@ -39,14 +39,11 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - build_runner: ^2.4.7 + build_runner: ^2.1.11 build_resolvers: ^2.0.9 mobx_codegen: ^2.0.7 hive_generator: ^1.1.3 -dependency_overrides: - watcher: ^1.1.0 - # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/cw_bitcoin_cash/pubspec.yaml b/cw_bitcoin_cash/pubspec.yaml index ceef539c3..37827f1ba 100644 --- a/cw_bitcoin_cash/pubspec.yaml +++ b/cw_bitcoin_cash/pubspec.yaml @@ -39,13 +39,10 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - build_runner: ^2.4.7 + build_runner: ^2.1.11 mobx_codegen: ^2.0.7 hive_generator: ^1.1.3 -dependency_overrides: - watcher: ^1.1.0 - # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/cw_core/pubspec.yaml b/cw_core/pubspec.yaml index 51d671dc7..04a840d4e 100644 --- a/cw_core/pubspec.yaml +++ b/cw_core/pubspec.yaml @@ -28,14 +28,11 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - build_runner: ^2.4.7 + build_runner: ^2.1.11 build_resolvers: ^2.0.9 mobx_codegen: ^2.0.7 hive_generator: ^2.0.1 -dependency_overrides: - watcher: ^1.1.0 - # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/cw_ethereum/pubspec.yaml b/cw_ethereum/pubspec.yaml index cbe6644a4..649ec574b 100644 --- a/cw_ethereum/pubspec.yaml +++ b/cw_ethereum/pubspec.yaml @@ -22,11 +22,7 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - build_runner: ^2.4.7 - -dependency_overrides: - watcher: ^1.1.0 - + build_runner: ^2.1.11 flutter: # assets: # - images/a_dot_burr.jpeg diff --git a/cw_evm/pubspec.yaml b/cw_evm/pubspec.yaml index eaafb8415..c202cc72a 100644 --- a/cw_evm/pubspec.yaml +++ b/cw_evm/pubspec.yaml @@ -27,14 +27,11 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - build_runner: ^2.4.7 + build_runner: ^2.1.11 mobx_codegen: ^2.0.7 hive_generator: ^1.1.3 flutter_lints: ^2.0.0 -dependency_overrides: - watcher: ^1.1.0 - flutter: # assets: # - images/a_dot_burr.jpeg diff --git a/cw_haven/pubspec.yaml b/cw_haven/pubspec.yaml index d868c986d..c215ab779 100644 --- a/cw_haven/pubspec.yaml +++ b/cw_haven/pubspec.yaml @@ -24,14 +24,11 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - build_runner: ^2.4.7 + build_runner: ^2.1.11 mobx_codegen: ^2.0.7 build_resolvers: ^2.0.9 hive_generator: ^1.1.3 -dependency_overrides: - watcher: ^1.1.0 - # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/cw_monero/pubspec.yaml b/cw_monero/pubspec.yaml index c49a541ab..a6fe7f967 100644 --- a/cw_monero/pubspec.yaml +++ b/cw_monero/pubspec.yaml @@ -26,14 +26,11 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - build_runner: ^2.4.7 + build_runner: ^2.1.11 build_resolvers: ^2.0.9 mobx_codegen: ^2.0.7 hive_generator: ^1.1.3 -dependency_overrides: - watcher: ^1.1.0 - # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/cw_nano/pubspec.yaml b/cw_nano/pubspec.yaml index 768c1bb4e..a4b8732fd 100644 --- a/cw_nano/pubspec.yaml +++ b/cw_nano/pubspec.yaml @@ -32,13 +32,10 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - build_runner: ^2.4.7 + build_runner: ^2.1.11 mobx_codegen: ^2.0.7 hive_generator: ^1.1.3 -dependency_overrides: - watcher: ^1.1.0 - # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/cw_polygon/pubspec.yaml b/cw_polygon/pubspec.yaml index 61a474002..505838d7c 100644 --- a/cw_polygon/pubspec.yaml +++ b/cw_polygon/pubspec.yaml @@ -28,10 +28,7 @@ dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^2.0.0 - build_runner: ^2.4.7 - -dependency_overrides: - watcher: ^1.1.0 + build_runner: ^2.1.11 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/cw_solana/pubspec.yaml b/cw_solana/pubspec.yaml index 6b59282b4..7e24983bf 100644 --- a/cw_solana/pubspec.yaml +++ b/cw_solana/pubspec.yaml @@ -26,13 +26,10 @@ dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^2.0.0 - build_runner: ^2.4.7 + build_runner: ^2.1.11 mobx_codegen: ^2.0.7 hive_generator: ^1.1.3 -dependency_overrides: - watcher: ^1.1.0 - flutter: # assets: # - images/a_dot_burr.jpeg diff --git a/lib/entities/biometric_auth.dart b/lib/entities/biometric_auth.dart index 463a22775..febbfa469 100644 --- a/lib/entities/biometric_auth.dart +++ b/lib/entities/biometric_auth.dart @@ -1,28 +1,32 @@ +import 'package:local_auth/local_auth.dart'; import 'package:flutter/services.dart'; -import 'package:flutter_local_authentication/flutter_local_authentication.dart'; +import 'package:cake_wallet/generated/i18n.dart'; class BiometricAuth { - final _flutterLocalAuthenticationPlugin = FlutterLocalAuthentication(); + final _localAuth = LocalAuthentication(); Future isAuthenticated() async { try { - final authenticated = await _flutterLocalAuthenticationPlugin.authenticate(); - return authenticated; - } catch (e) { + return await _localAuth.authenticate( + localizedReason: S.current.biometric_auth_reason, + options: AuthenticationOptions( + biometricOnly: true, + useErrorDialogs: true, + stickyAuth: false)); + } on PlatformException catch (e) { print(e); } + return false; } Future canCheckBiometrics() async { - bool canAuthenticate; try { - canAuthenticate = await _flutterLocalAuthenticationPlugin.canAuthenticate(); - } catch (error) { - print("Exception checking support. $error"); - canAuthenticate = false; + return await _localAuth.canCheckBiometrics; + } on PlatformException catch (e) { + print(e); } - return canAuthenticate; + return false; } } diff --git a/lib/locales/hausa_intl.dart b/lib/locales/hausa_intl.dart index 6cf757b60..749d39a4d 100644 --- a/lib/locales/hausa_intl.dart +++ b/lib/locales/hausa_intl.dart @@ -751,50 +751,6 @@ class HaMaterialLocalizations extends GlobalMaterialLocalizations { @override String get scrimOnTapHintRaw => "Scrip on Tap"; - - @override - // TODO: implement collapsedHint - String get collapsedHint => "collapsedHint"; - - @override - // TODO: implement expandedHint - String get expandedHint => "expandedHint"; - - @override - // TODO: implement expansionTileCollapsedHint - String get expansionTileCollapsedHint => "expansionTileCollapsedHint"; - - @override - // TODO: implement expansionTileCollapsedTapHint - String get expansionTileCollapsedTapHint => "expansionTileCollapsedTapHint"; - - @override - // TODO: implement expansionTileExpandedHint - String get expansionTileExpandedHint => "expansionTileExpandedHint"; - - @override - // TODO: implement expansionTileExpandedTapHint - String get expansionTileExpandedTapHint => "expansionTileExpandedTapHint"; - - @override - // TODO: implement scanTextButtonLabel - String get scanTextButtonLabel => "scanTextButtonLabel"; - - @override - // TODO: implement lookUpButtonLabel - String get lookUpButtonLabel => "lookUpButtonLabel"; - - @override - // TODO: implement menuDismissLabel - String get menuDismissLabel => "menuDismissLabel"; - - @override - // TODO: implement searchWebButtonLabel - String get searchWebButtonLabel => "searchWebButtonLabel"; - - @override - // TODO: implement shareButtonLabel - String get shareButtonLabel => "shareButtonLabel"; } /// Cupertino Support @@ -999,24 +955,4 @@ class HaCupertinoLocalizations extends GlobalCupertinoLocalizations { @override String get noSpellCheckReplacementsLabel => ""; - - @override - // TODO: implement clearButtonLabel - String get clearButtonLabel => "clearButtonLabel"; - - @override - // TODO: implement lookUpButtonLabel - String get lookUpButtonLabel => "lookUpButtonLabel"; - - @override - // TODO: implement menuDismissLabel - String get menuDismissLabel => "menuDismissLabel"; - - @override - // TODO: implement searchWebButtonLabel - String get searchWebButtonLabel => "searchWebButtonLabel"; - - @override - // TODO: implement shareButtonLabel - String get shareButtonLabel => "shareButtonLabel"; } diff --git a/lib/locales/yoruba_intl.dart b/lib/locales/yoruba_intl.dart index 3c720b80e..889c21cb7 100644 --- a/lib/locales/yoruba_intl.dart +++ b/lib/locales/yoruba_intl.dart @@ -1,3 +1,4 @@ + import 'dart:async'; import 'package:flutter/cupertino.dart'; @@ -163,62 +164,62 @@ const yoDateSymbols = { 'ọjọ́ Àbámẹ́ta', ], 'STANDALONEWEEKDAYS': [ - 'Ọjọ́ Ajé', - 'Ọjọ́ Ìsẹ́gun', - 'Ọjọ́ Ìsẹ́gun-Ẹtì', - 'Ọjọ́ Ìsẹ́gun-Ọ̀rú', - 'Ọjọ́ Àìkú', - 'Ọjọ́ Jímọ̀', - 'Ọjọ́ Àbámẹ́ta', - ], - 'SHORTWEEKDAYS': [ - 'Ajé', - 'Ìsẹ́gun', - 'Ìsẹ́gun-Ẹtì', - 'Ìsẹ́gun-Ọ̀rú', - 'Àìkú', - 'Jímọ̀', - 'Àbámẹ́ta', - ], - 'STANDALONESHORTWEEKDAYS': [ - 'Ajé', - 'Ìsẹ́gun', - 'Ìsẹ́gun-Ẹtì', - 'Ìsẹ́gun-Ọ̀rú', - 'Àìkú', - 'Jímọ̀', - 'Àbámẹ́ta', - ], - 'NARROWWEEKDAYS': [ - 'A', - 'A', - 'Ì', - 'A', - 'À', - 'J', - 'À', - ], - 'STANDALONENARROWWEEKDAYS': [ - 'A', - 'A', - 'Ì', - 'A', - 'À', - 'J', - 'À', - ], - 'SHORTQUARTERS': [ - 'K1', - 'K2', - 'K3', - 'K4', - ], - 'QUARTERS': [ - '1. kwata', - '2. kwata', - '3. kwata', - '4. kwata', - ], +'Ọjọ́ Ajé', +'Ọjọ́ Ìsẹ́gun', +'Ọjọ́ Ìsẹ́gun-Ẹtì', +'Ọjọ́ Ìsẹ́gun-Ọ̀rú', +'Ọjọ́ Àìkú', +'Ọjọ́ Jímọ̀', +'Ọjọ́ Àbámẹ́ta', +], +'SHORTWEEKDAYS': [ +'Ajé', +'Ìsẹ́gun', +'Ìsẹ́gun-Ẹtì', +'Ìsẹ́gun-Ọ̀rú', +'Àìkú', +'Jímọ̀', +'Àbámẹ́ta', +], +'STANDALONESHORTWEEKDAYS': [ +'Ajé', +'Ìsẹ́gun', +'Ìsẹ́gun-Ẹtì', +'Ìsẹ́gun-Ọ̀rú', +'Àìkú', +'Jímọ̀', +'Àbámẹ́ta', +], +'NARROWWEEKDAYS': [ +'A', +'A', +'Ì', +'A', +'À', +'J', +'À', +], +'STANDALONENARROWWEEKDAYS': [ +'A', +'A', +'Ì', +'A', +'À', +'J', +'À', +], +'SHORTQUARTERS': [ +'K1', +'K2', +'K3', +'K4', +], +'QUARTERS': [ +'1. kwata', +'2. kwata', +'3. kwata', +'4. kwata', +], 'AMPMS': [ 'a.m.', 'p.m.', @@ -315,339 +316,339 @@ class YoMaterialLocalizations extends GlobalMaterialLocalizations { }); // #docregion Getters - @override - String get moreButtonTooltip => r'Kò sí ìròhùn tí ó múni'; +@override +String get moreButtonTooltip => r'Kò sí ìròhùn tí ó múni'; - @override - String get aboutListTileTitleRaw => r'Fun Àpótí àwọn $applicationname'; +@override +String get aboutListTileTitleRaw => r'Fun Àpótí àwọn $applicationname'; - @override - String get alertDialogLabel => r'Ìròhùn Àlàyé'; +@override +String get alertDialogLabel => r'Ìròhùn Àlàyé'; // #enddocregion Getters - @override - String get anteMeridiemAbbreviation => r'AM'; +@override +String get anteMeridiemAbbreviation => r'AM'; - @override - String get backButtonTooltip => r'Fíran'; +@override +String get backButtonTooltip => r'Fíran'; - @override - String get cancelButtonLabel => r'FAGILE'; +@override +String get cancelButtonLabel => r'FAGILE'; - @override - String get closeButtonLabel => r'KÚ'; +@override +String get closeButtonLabel => r'KÚ'; - @override - String get closeButtonTooltip => r'Kú'; +@override +String get closeButtonTooltip => r'Kú'; - @override - String get collapsedIconTapHint => r'Tá'; +@override +String get collapsedIconTapHint => r'Tá'; - @override - String get continueButtonLabel => r'TÓ WÁ'; +@override +String get continueButtonLabel => r'TÓ WÁ'; - @override - String get copyButtonLabel => r'DÚPLÍKÉTÍ'; +@override +String get copyButtonLabel => r'DÚPLÍKÉTÍ'; - @override - String get cutButtonLabel => r'TÒ'; +@override +String get cutButtonLabel => r'TÒ'; - @override - String get deleteButtonTooltip => r'Máa kú'; +@override +String get deleteButtonTooltip => r'Máa kú'; - @override - String get dialogLabel => r'Ìròhùn'; +@override +String get dialogLabel => r'Ìròhùn'; - @override - String get drawerLabel => r'Àgbèjọ àwọn àpọ̀tí'; +@override +String get drawerLabel => r'Àgbèjọ àwọn àpọ̀tí'; - @override - String get expandedIconTapHint => r'Tá'; +@override +String get expandedIconTapHint => r'Tá'; - @override - String get firstPageTooltip => r'Ojú ewe'; +@override +String get firstPageTooltip => r'Ojú ewe'; - @override - String get hideAccountsLabel => r'Fí èrò àpótí wáyé sílẹ̀'; +@override +String get hideAccountsLabel => r'Fí èrò àpótí wáyé sílẹ̀'; - @override - String get lastPageTooltip => r'Ojú ayé'; +@override +String get lastPageTooltip => r'Ojú ayé'; - @override - String get licensesPageTitle => r'Ìròhùn Ọdún'; +@override +String get licensesPageTitle => r'Ìròhùn Ọdún'; - @override - String get modalBarrierDismissLabel => r'Sọ'; +@override +String get modalBarrierDismissLabel => r'Sọ'; - @override - String get nextMonthTooltip => r'Oṣù kọja'; +@override +String get nextMonthTooltip => r'Oṣù kọja'; - @override - String get nextPageTooltip => r'Ojú ọjọ́ kẹta'; +@override +String get nextPageTooltip => r'Ojú ọjọ́ kẹta'; - @override - String get okButtonLabel => r'Ò daájú'; - @override +@override +String get okButtonLabel => r'Ò daájú'; +@override // A custom drawer tooltip message. - String get openAppDrawerTooltip => r'Aya ntọju Iwe Awọn Aka'; +String get openAppDrawerTooltip => r'Aya ntọju Iwe Awọn Aka'; // #docregion Raw - @override - String get pageRowsInfoTitleRaw => r'$firstRow–$lastRow lati $rowCount'; +@override +String get pageRowsInfoTitleRaw => r'$firstRow–$lastRow lati $rowCount'; - @override - String get pageRowsInfoTitleApproximateRaw => r'$firstRow–$lastRow lati kiakia $rowCount'; +@override +String get pageRowsInfoTitleApproximateRaw => r'$firstRow–$lastRow lati kiakia $rowCount'; // #enddocregion Raw - @override - String get pasteButtonLabel => r'TÌ'; +@override +String get pasteButtonLabel => r'TÌ'; - @override - String get popupMenuLabel => r'Meniu Pop-up'; +@override +String get popupMenuLabel => r'Meniu Pop-up'; - @override - String get menuBarMenuLabel => r'Meniu Akọkọ'; +@override +String get menuBarMenuLabel => r'Meniu Akọkọ'; - @override - String get postMeridiemAbbreviation => r'PM'; +@override +String get postMeridiemAbbreviation => r'PM'; - @override - String get previousMonthTooltip => r'Oṣu Kanakana'; +@override +String get previousMonthTooltip => r'Oṣu Kanakana'; - @override - String get previousPageTooltip => r'Ojú ewé akọkọ kan'; +@override +String get previousPageTooltip => r'Ojú ewé akọkọ kan'; - @override - String get refreshIndicatorSemanticLabel => r'Gbiyanju'; +@override +String get refreshIndicatorSemanticLabel => r'Gbiyanju'; - @override - String? get remainingTextFieldCharacterCountFew => null; +@override +String? get remainingTextFieldCharacterCountFew => null; - @override - String? get remainingTextFieldCharacterCountMany => null; +@override +String? get remainingTextFieldCharacterCountMany => null; - @override - String get remainingTextFieldCharacterCountOne => r'1 àmì báálẹ̀'; +@override +String get remainingTextFieldCharacterCountOne => r'1 àmì báálẹ̀'; - @override - String get remainingTextFieldCharacterCountOther => r'$remainingCount àmì báálẹ̀'; +@override +String get remainingTextFieldCharacterCountOther => r'$remainingCount àmì báálẹ̀'; - @override - String? get remainingTextFieldCharacterCountTwo => null; +@override +String? get remainingTextFieldCharacterCountTwo => null; - @override - String get remainingTextFieldCharacterCountZero => r'Kò sí ìwọlé létà láti ń ṣe'; +@override +String get remainingTextFieldCharacterCountZero => r'Kò sí ìwọlé létà láti ń ṣe'; - @override - String get reorderItemDown => r'Jù sí ilẹ'; +@override +String get reorderItemDown => r'Jù sí ilẹ'; - @override - String get reorderItemLeft => r'Jù sí àrà'; +@override +String get reorderItemLeft => r'Jù sí àrà'; - @override - String get reorderItemRight => r'Jù sí òtútù'; +@override +String get reorderItemRight => r'Jù sí òtútù'; - @override - String get reorderItemToEnd => r'Jù sí ìbẹ̀jì'; +@override +String get reorderItemToEnd => r'Jù sí ìbẹ̀jì'; - @override - String get reorderItemToStart => r'Jù sí àkọ́kọ́'; +@override +String get reorderItemToStart => r'Jù sí àkọ́kọ́'; - @override - String get reorderItemUp => r'Jù sí ọ̀rùn'; +@override +String get reorderItemUp => r'Jù sí ọ̀rùn'; - @override - String get rowsPerPageTitle => r'Ìlò Fún àwọn Ìtọ́kasíwájú:'; +@override +String get rowsPerPageTitle => r'Ìlò Fún àwọn Ìtọ́kasíwájú:'; - @override - ScriptCategory get scriptCategory => ScriptCategory.englishLike; +@override +ScriptCategory get scriptCategory => ScriptCategory.englishLike; - @override - String get searchFieldLabel => 'Ṣẹda'; +@override +String get searchFieldLabel => 'Ṣẹda'; - @override - String get selectAllButtonLabel => 'FADỌHỌN DỌFÚN GBÁJÚMỌ̀'; +@override +String get selectAllButtonLabel => 'FADỌHỌN DỌFÚN GBÁJÚMỌ̀'; - @override - String? get selectedRowCountTitleFew => null; +@override +String? get selectedRowCountTitleFew => null; - @override - String? get selectedRowCountTitleMany => null; +@override +String? get selectedRowCountTitleMany => null; - @override - String get selectedRowCountTitleOne => '1 káyé'; +@override +String get selectedRowCountTitleOne => '1 káyé'; - @override - String get selectedRowCountTitleOther => r'$selectedRowCount káyé'; +@override +String get selectedRowCountTitleOther => r'$selectedRowCount káyé'; - @override - String? get selectedRowCountTitleTwo => null; +@override +String? get selectedRowCountTitleTwo => null; - @override - String get selectedRowCountTitleZero => 'Kò sí káyé ti o wọlé'; +@override +String get selectedRowCountTitleZero => 'Kò sí káyé ti o wọlé'; - @override - String get showAccountsLabel => 'Fi iyipada mu kọ'; +@override +String get showAccountsLabel => 'Fi iyipada mu kọ'; - @override - String get showMenuTooltip => 'Fi Meniu mu kọ'; +@override +String get showMenuTooltip => 'Fi Meniu mu kọ'; - @override - String get signedInLabel => 'Ọ̀nà'; +@override +String get signedInLabel => 'Ọ̀nà'; +@override +String get tabLabelRaw => r'Àwọn tabin $tabIndex lati $tabCount'; + @override - String get tabLabelRaw => r'Àwọn tabin $tabIndex lati $tabCount'; +TimeOfDayFormat get timeOfDayFormatRaw => TimeOfDayFormat.h_colon_mm_space_a; - @override - TimeOfDayFormat get timeOfDayFormatRaw => TimeOfDayFormat.h_colon_mm_space_a; +@override +String get timePickerHourModeAnnouncement => 'Tuntun waqtu lọ'; - @override - String get timePickerHourModeAnnouncement => 'Tuntun waqtu lọ'; +@override +String get timePickerMinuteModeAnnouncement => 'Tuntun daɗi minti'; - @override - String get timePickerMinuteModeAnnouncement => 'Tuntun daɗi minti'; +@override +String get viewLicensesButtonLabel => 'WO NIKI'; - @override - String get viewLicensesButtonLabel => 'WO NIKI'; +@override +List get narrowWeekdays => const ['L', 'L', 'A', 'O', 'Ọ', 'Ẹ', 'Ẹ']; - @override - List get narrowWeekdays => const ['L', 'L', 'A', 'O', 'Ọ', 'Ẹ', 'Ẹ']; +@override +int get firstDayOfWeekIndex => 0; - @override - int get firstDayOfWeekIndex => 0; +static const LocalizationsDelegate delegate = +_YoMaterialLocalizationsDelegate(); - static const LocalizationsDelegate delegate = - _YoMaterialLocalizationsDelegate(); +@override +String get calendarModeButtonLabel => 'Tọ́rọ̀ kálẹ̀ndà'; - @override - String get calendarModeButtonLabel => 'Tọ́rọ̀ kálẹ̀ndà'; +@override +String get dateHelpText => 'mm/dd/yyyy'; - @override - String get dateHelpText => 'mm/dd/yyyy'; +@override +String get dateInputLabel => 'Firanṣẹ̀ Ọjọ́'; - @override - String get dateInputLabel => 'Firanṣẹ̀ Ọjọ́'; +@override +String get dateOutOfRangeLabel => 'Nínú iwọ̀ lọ́wọ́'; - @override - String get dateOutOfRangeLabel => 'Nínú iwọ̀ lọ́wọ́'; +@override +String get datePickerHelpText => 'WÁSÍ'; - @override - String get datePickerHelpText => 'WÁSÍ'; +@override +String get dateRangeEndDateSemanticLabelRaw => r'Ọjọ́ tuntun to ṣà'; - @override - String get dateRangeEndDateSemanticLabelRaw => r'Ọjọ́ tuntun to ṣà'; - - @override - String get dateRangeEndLabel => 'Ọjọ́ tuntun to ṣà'; +@override +String get dateRangeEndLabel => 'Ọjọ́ tuntun to ṣà'; - @override - String get dateRangePickerHelpText => 'WÁSÍ ÌGBÀ'; +@override +String get dateRangePickerHelpText => 'WÁSÍ ÌGBÀ'; - @override - String get dateRangeStartDateSemanticLabelRaw => 'Ọjọ́ tuntun ti dá'; +@override +String get dateRangeStartDateSemanticLabelRaw => 'Ọjọ́ tuntun ti dá'; - @override - String get dateRangeStartLabel => 'Ọjọ́ tuntun ti dá'; +@override +String get dateRangeStartLabel => 'Ọjọ́ tuntun ti dá'; - @override - String get dateSeparator => '/'; +@override +String get dateSeparator => '/'; - @override - String get dialModeButtonLabel => 'Tọ́rọ̀ wakati'; +@override +String get dialModeButtonLabel => 'Tọ́rọ̀ wakati'; - @override - String get inputDateModeButtonLabel => 'Tọ́rọ̀ firanṣẹ̀ ọjọ́'; +@override +String get inputDateModeButtonLabel => 'Tọ́rọ̀ firanṣẹ̀ ọjọ́'; - @override - String get inputTimeModeButtonLabel => 'Tọ́rọ̀ wakati bayi lọ́wọ́'; +@override +String get inputTimeModeButtonLabel => 'Tọ́rọ̀ wakati bayi lọ́wọ́'; - @override - String get invalidDateFormatLabel => 'Akọ́kọ́tọ́ tó jẹ́kúnrin'; +@override +String get invalidDateFormatLabel => 'Akọ́kọ́tọ́ tó jẹ́kúnrin'; - @override - String get invalidDateRangeLabel => 'Àmì jẹ́ káàkiri lẹ́yìn ilé'; +@override +String get invalidDateRangeLabel => 'Àmì jẹ́ káàkiri lẹ́yìn ilé'; - @override - String get invalidTimeLabel => 'Akọ́kọ́tọ́ àkójọ ìwádìí'; +@override +String get invalidTimeLabel => 'Akọ́kọ́tọ́ àkójọ ìwádìí'; - @override - String get licensesPackageDetailTextOther => r'$licenseCount àwọn níkí'; +@override +String get licensesPackageDetailTextOther => r'$licenseCount àwọn níkí'; - @override - String get saveButtonLabel => 'TÙN DÁRA'; +@override +String get saveButtonLabel => 'TÙN DÁRA'; - @override - String get selectYearSemanticsLabel => 'Fọ́ọ̀ shẹ́kàrà'; +@override +String get selectYearSemanticsLabel => 'Fọ́ọ̀ shẹ́kàrà'; - @override - String get timePickerDialHelpText => 'WÁSÍ WÁKÀTÌ'; +@override +String get timePickerDialHelpText => 'WÁSÍ WÁKÀTÌ'; - @override - String get timePickerHourLabel => 'Wákàtì àṣà'; +@override +String get timePickerHourLabel => 'Wákàtì àṣà'; - @override - String get timePickerInputHelpText => 'Shìgárà wákàtì'; +@override +String get timePickerInputHelpText => 'Shìgárà wákàtì'; - @override - String get timePickerMinuteLabel => 'Mìntì'; +@override +String get timePickerMinuteLabel => 'Mìntì'; - @override - String get unspecifiedDate => 'Ọjọ̀kúnrin'; +@override +String get unspecifiedDate => 'Ọjọ̀kúnrin'; - @override - String get unspecifiedDateRange => 'Ọjọ̀kúnrin àdáyọ̀'; +@override +String get unspecifiedDateRange => 'Ọjọ̀kúnrin àdáyọ̀'; - @override - String get keyboardKeyAlt => 'Alt'; +@override +String get keyboardKeyAlt => 'Alt'; - @override - String get keyboardKeyAltGraph => 'AltGraph'; +@override +String get keyboardKeyAltGraph => 'AltGraph'; - @override - String get keyboardKeyBackspace => 'Báckspàcè'; +@override +String get keyboardKeyBackspace => 'Báckspàcè'; - @override - String get keyboardKeyCapsLock => 'Caps Lock'; +@override +String get keyboardKeyCapsLock => 'Caps Lock'; - @override - String get keyboardKeyChannelDown => 'Báyàkàmmàlàsàké'; +@override +String get keyboardKeyChannelDown => 'Báyàkàmmàlàsàké'; - @override - String get keyboardKeyChannelUp => 'Yíkàmmàlàsàké'; +@override +String get keyboardKeyChannelUp => 'Yíkàmmàlàsàké'; - @override - String get keyboardKeyControl => 'Kọ́ntírọ̀l'; +@override +String get keyboardKeyControl => 'Kọ́ntírọ̀l'; - @override - String get keyboardKeyDelete => 'Shápè'; +@override +String get keyboardKeyDelete => 'Shápè'; - @override - String get keyboardKeyEject => 'Èjẹ̀tì'; +@override +String get keyboardKeyEject => 'Èjẹ̀tì'; - @override - String get keyboardKeyEnd => 'Tàbí'; +@override +String get keyboardKeyEnd => 'Tàbí'; - @override - String get keyboardKeyEscape => 'Tòkè'; +@override +String get keyboardKeyEscape => 'Tòkè'; @override - String get keyboardKeyFn => 'Fn'; +String get keyboardKeyFn => 'Fn'; - @override - String get keyboardKeyHome => 'Ile'; +@override +String get keyboardKeyHome => 'Ile'; - @override - String get keyboardKeyInsert => 'Fi sori'; +@override +String get keyboardKeyInsert => 'Fi sori'; - @override - String get keyboardKeyMeta => 'Meta'; +@override +String get keyboardKeyMeta => 'Meta'; - @override - String get keyboardKeyMetaMacOs => 'Amfani pẹlu Command'; +@override +String get keyboardKeyMetaMacOs => 'Amfani pẹlu Command'; - @override - String get keyboardKeyMetaWindows => 'Windows'; +@override +String get keyboardKeyMetaWindows => 'Windows'; @override String get keyboardKeyNumLock => 'Num Lock'; @@ -750,50 +751,6 @@ class YoMaterialLocalizations extends GlobalMaterialLocalizations { @override String get scrimOnTapHintRaw => "Scrip on Tap"; - - @override - // TODO: implement collapsedHint - String get collapsedHint => "collapsedHint"; - - @override - // TODO: implement expandedHint - String get expandedHint => "expandedHint"; - - @override - // TODO: implement expansionTileCollapsedHint - String get expansionTileCollapsedHint => "expansionTileCollapsedHint"; - - @override - // TODO: implement expansionTileCollapsedTapHint - String get expansionTileCollapsedTapHint => "expansionTileCollapsedTapHint"; - - @override - // TODO: implement expansionTileExpandedHint - String get expansionTileExpandedHint => "expansionTileExpandedHint"; - - @override - // TODO: implement expansionTileExpandedTapHint - String get expansionTileExpandedTapHint => "expansionTileExpandedTapHint"; - - @override - // TODO: implement scanTextButtonLabel - String get scanTextButtonLabel => "scanTextButtonLabel"; - - @override - // TODO: implement lookUpButtonLabel - String get lookUpButtonLabel => "lookUpButtonLabel"; - - @override - // TODO: implement menuDismissLabel - String get menuDismissLabel => "menuDismissLabel"; - - @override - // TODO: implement searchWebButtonLabel - String get searchWebButtonLabel => "searchWebButtonLabel"; - - @override - // TODO: implement shareButtonLabel - String get shareButtonLabel => "shareButtonLabel"; } /// Cupertino Support @@ -864,158 +821,138 @@ class YoCupertinoLocalizations extends GlobalCupertinoLocalizations { required super.singleDigitSecondFormat, }); - @override - String get alertDialogLabel => 'Àdàkárò'; +@override +String get alertDialogLabel => 'Àdàkárò'; - @override - String get anteMeridiemAbbreviation => 'AM'; +@override +String get anteMeridiemAbbreviation => 'AM'; - @override - String get copyButtonLabel => 'Kòpy'; +@override +String get copyButtonLabel => 'Kòpy'; - @override - String get cutButtonLabel => 'Kọ́t'; +@override +String get cutButtonLabel => 'Kọ́t'; - @override - String get datePickerDateOrderString => 'mdy'; +@override +String get datePickerDateOrderString => 'mdy'; - @override - String get datePickerDateTimeOrderString => 'date_time_dayPeriod'; +@override +String get datePickerDateTimeOrderString => 'date_time_dayPeriod'; - @override - String? get datePickerHourSemanticsLabelFew => null; +@override +String? get datePickerHourSemanticsLabelFew => null; - @override - String? get datePickerHourSemanticsLabelMany => null; +@override +String? get datePickerHourSemanticsLabelMany => null; - @override - String? get datePickerHourSemanticsLabelOne => r"$hour o'clock"; +@override +String? get datePickerHourSemanticsLabelOne => r"$hour o'clock"; - @override - String get datePickerHourSemanticsLabelOther => r"$hour o'clock"; +@override +String get datePickerHourSemanticsLabelOther => r"$hour o'clock"; - @override - String? get datePickerHourSemanticsLabelTwo => null; +@override +String? get datePickerHourSemanticsLabelTwo => null; - @override - String? get datePickerHourSemanticsLabelZero => null; +@override +String? get datePickerHourSemanticsLabelZero => null; - @override - String? get datePickerMinuteSemanticsLabelFew => null; +@override +String? get datePickerMinuteSemanticsLabelFew => null; - @override - String? get datePickerMinuteSemanticsLabelMany => null; +@override +String? get datePickerMinuteSemanticsLabelMany => null; - @override - String? get datePickerMinuteSemanticsLabelOne => '1 wakati'; +@override +String? get datePickerMinuteSemanticsLabelOne => '1 wakati'; - @override - String get datePickerMinuteSemanticsLabelOther => r'$minute wakati'; +@override +String get datePickerMinuteSemanticsLabelOther => r'$minute wakati'; - @override - String? get datePickerMinuteSemanticsLabelTwo => null; +@override +String? get datePickerMinuteSemanticsLabelTwo => null; - @override - String? get datePickerMinuteSemanticsLabelZero => null; +@override +String? get datePickerMinuteSemanticsLabelZero => null; - @override - String get modalBarrierDismissLabel => 'Búta'; +@override +String get modalBarrierDismissLabel => 'Búta'; - @override - String get pasteButtonLabel => 'Tẹ́ẹ́'; +@override +String get pasteButtonLabel => 'Tẹ́ẹ́'; - @override - String get postMeridiemAbbreviation => 'PM'; +@override +String get postMeridiemAbbreviation => 'PM'; - @override - String get searchTextFieldPlaceholderLabel => 'Wúró àtúntà'; +@override +String get searchTextFieldPlaceholderLabel => 'Wúró àtúntà'; - @override - String get selectAllButtonLabel => 'Fírànsé gbógbo'; +@override +String get selectAllButtonLabel => 'Fírànsé gbógbo'; - @override - String get tabSemanticsLabelRaw => r'Tab $tabIndex nínú $tabCount'; +@override +String get tabSemanticsLabelRaw => r'Tab $tabIndex nínú $tabCount'; - @override - String? get timerPickerHourLabelFew => null; +@override +String? get timerPickerHourLabelFew => null; - @override - String? get timerPickerHourLabelMany => null; +@override +String? get timerPickerHourLabelMany => null; - @override - String? get timerPickerHourLabelOne => 'òǹdì'; +@override +String? get timerPickerHourLabelOne => 'òǹdì'; - @override - String get timerPickerHourLabelOther => 'òǹdì'; +@override +String get timerPickerHourLabelOther => 'òǹdì'; - @override - String? get timerPickerHourLabelTwo => null; +@override +String? get timerPickerHourLabelTwo => null; - @override - String? get timerPickerHourLabelZero => null; +@override +String? get timerPickerHourLabelZero => null; - @override - String? get timerPickerMinuteLabelFew => null; +@override +String? get timerPickerMinuteLabelFew => null; - @override - String? get timerPickerMinuteLabelMany => null; +@override +String? get timerPickerMinuteLabelMany => null; - @override - String? get timerPickerMinuteLabelOne => 'wakati.'; +@override +String? get timerPickerMinuteLabelOne => 'wakati.'; - @override - String get timerPickerMinuteLabelOther => 'wakati.'; +@override +String get timerPickerMinuteLabelOther => 'wakati.'; - @override - String? get timerPickerMinuteLabelTwo => null; +@override +String? get timerPickerMinuteLabelTwo => null; - @override - String? get timerPickerMinuteLabelZero => null; +@override +String? get timerPickerMinuteLabelZero => null; - @override - String? get timerPickerSecondLabelFew => null; +@override +String? get timerPickerSecondLabelFew => null; - @override - String? get timerPickerSecondLabelMany => null; +@override +String? get timerPickerSecondLabelMany => null; - @override - String? get timerPickerSecondLabelOne => 'dákìkà.'; +@override +String? get timerPickerSecondLabelOne => 'dákìkà.'; - @override - String get timerPickerSecondLabelOther => 'dákìkà.'; +@override +String get timerPickerSecondLabelOther => 'dákìkà.'; - @override - String? get timerPickerSecondLabelTwo => null; +@override +String? get timerPickerSecondLabelTwo => null; - @override - String? get timerPickerSecondLabelZero => null; +@override +String? get timerPickerSecondLabelZero => null; - @override - String get todayLabel => 'Oyọ'; +@override +String get todayLabel => 'Oyọ'; static const LocalizationsDelegate delegate = _YoCupertinoLocalizationsDelegate(); @override String get noSpellCheckReplacementsLabel => ""; - - @override - // TODO: implement clearButtonLabel - String get clearButtonLabel => "clearButtonLabel"; - - @override - // TODO: implement lookUpButtonLabel - String get lookUpButtonLabel => "lookUpButtonLabel"; - - @override - // TODO: implement menuDismissLabel - String get menuDismissLabel => "menuDismissLabel"; - - @override - // TODO: implement searchWebButtonLabel - String get searchWebButtonLabel => "searchWebButtonLabel"; - - @override - // TODO: implement shareButtonLabel - String get shareButtonLabel => "shareButtonLabel"; } diff --git a/lib/src/screens/settings/security_backup_page.dart b/lib/src/screens/settings/security_backup_page.dart index 1f0f58ad4..e559e9b15 100644 --- a/lib/src/screens/settings/security_backup_page.dart +++ b/lib/src/screens/settings/security_backup_page.dart @@ -1,5 +1,3 @@ -import 'dart:io'; - import 'package:cake_wallet/core/auth_service.dart'; import 'package:cake_wallet/entities/pin_code_required_duration.dart'; import 'package:cake_wallet/routes.dart'; @@ -60,7 +58,7 @@ class SecurityBackupPage extends BasePage { .shouldRequireTOTP2FAForAllSecurityAndBackupSettings, ), ), - if (DeviceInfo.instance.isMobile || Platform.isMacOS || Platform.isLinux) + if (DeviceInfo.instance.isMobile) Observer(builder: (_) { return SettingsSwitcherCell( title: S.current.settings_allow_biometrical_authentication, diff --git a/lib/src/screens/settings/tor_page.dart b/lib/src/screens/settings/tor_page.dart index 2f544be35..ae1ef1677 100644 --- a/lib/src/screens/settings/tor_page.dart +++ b/lib/src/screens/settings/tor_page.dart @@ -146,7 +146,7 @@ class ConnectScreen extends StatelessWidget { ElevatedButton( onPressed: connect, style: ElevatedButton.styleFrom( - // primary: Colors.blue, + primary: Colors.blue, padding: EdgeInsets.symmetric(horizontal: 40, vertical: 15), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(30), @@ -211,7 +211,7 @@ class DisconnectScreen extends StatelessWidget { ElevatedButton( onPressed: disconnect, style: ElevatedButton.styleFrom( - // primary: Colors.red, + primary: Colors.red, padding: EdgeInsets.symmetric(horizontal: 40, vertical: 15), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(30), diff --git a/lib/src/widgets/validable_annotated_editable_text.dart b/lib/src/widgets/validable_annotated_editable_text.dart index 7ea928d8a..6c3fc4f16 100644 --- a/lib/src/widgets/validable_annotated_editable_text.dart +++ b/lib/src/widgets/validable_annotated_editable_text.dart @@ -1,14 +1,8 @@ +import 'package:cake_wallet/core/seed_validator.dart'; +import 'package:cw_core/wallet_type.dart'; import 'package:flutter/material.dart'; - -extension Compare on Comparable { - bool operator <=(T other) => compareTo(other) <= 0; - bool operator >=(T other) => compareTo(other) >= 0; - bool operator <(T other) => compareTo(other) < 0; - bool operator >(T other) => compareTo(other) > 0; -} - -class Annotation implements Comparable { +class Annotation extends Comparable { Annotation({required this.range, required this.style}); final TextRange range; @@ -18,7 +12,7 @@ class Annotation implements Comparable { int compareTo(Annotation other) => range.start.compareTo(other.range.start); } -class TextAnnotation implements Comparable { +class TextAnnotation extends Comparable { TextAnnotation({required this.text, required this.style}); final TextStyle style; diff --git a/lib/view_model/auth_view_model.dart b/lib/view_model/auth_view_model.dart index 0e6590845..e50f4db0c 100644 --- a/lib/view_model/auth_view_model.dart +++ b/lib/view_model/auth_view_model.dart @@ -1,6 +1,5 @@ import 'dart:async'; import 'package:flutter/material.dart'; -import 'package:flutter_local_authentication/flutter_local_authentication.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:mobx/mobx.dart'; import 'package:cake_wallet/view_model/auth_state.dart'; @@ -106,14 +105,16 @@ abstract class AuthViewModelBase with Store { @action Future biometricAuth() async { - final _flutterLocalAuthenticationPlugin = FlutterLocalAuthentication(); - try { - final authenticated = await _flutterLocalAuthenticationPlugin.authenticate(); - if (!authenticated) { - throw Exception('Biometric authentication failed'); + final canBiometricAuth = await _biometricAuth.canCheckBiometrics(); + + if (canBiometricAuth) { + final isAuthenticated = await _biometricAuth.isAuthenticated(); + + if (isAuthenticated) { + state = ExecutedSuccessfullyState(); + } } - state = ExecutedSuccessfullyState(); } catch (e) { state = FailureState(e.toString()); } diff --git a/pubspec_base.yaml b/pubspec_base.yaml index e1022864c..3ec3e7978 100644 --- a/pubspec_base.yaml +++ b/pubspec_base.yaml @@ -33,8 +33,8 @@ dependencies: dio: ^4.0.6 hive: ^2.2.3 hive_flutter: ^1.1.0 + local_auth: ^2.1.0 local_auth_android: 1.0.21 - flutter_local_authentication: ^1.2.0 package_info: ^2.0.0 #package_info_plus: ^1.4.2 devicelocale: diff --git a/pubspec_description.yaml b/pubspec_description.yaml index b51fe96d6..ebb6bf001 100644 --- a/pubspec_description.yaml +++ b/pubspec_description.yaml @@ -4,4 +4,4 @@ version: 0.0.0 publish_to: none environment: - sdk: ">=3.1.0 <4.0.0" \ No newline at end of file + sdk: ">=2.17.5 <3.0.0" \ No newline at end of file From 65799a8764b339c2db329400d74bd7462632e63d Mon Sep 17 00:00:00 2001 From: Adegoke David <64401859+Blazebrain@users.noreply.github.com> Date: Wed, 24 Apr 2024 03:04:16 +0100 Subject: [PATCH 04/17] fix: Issue with the privateKey of Solana wallets being different accross various apps (#1400) --- cw_solana/lib/solana_wallet.dart | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/cw_solana/lib/solana_wallet.dart b/cw_solana/lib/solana_wallet.dart index ad58c4293..43a6d0b83 100644 --- a/cw_solana/lib/solana_wallet.dart +++ b/cw_solana/lib/solana_wallet.dart @@ -27,6 +27,7 @@ import 'package:hex/hex.dart'; import 'package:hive/hive.dart'; import 'package:mobx/mobx.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import 'package:solana/base58.dart'; import 'package:solana/metaplex.dart' as metaplex; import 'package:solana/solana.dart'; @@ -108,7 +109,17 @@ abstract class SolanaWalletBase String? get seed => _mnemonic; @override - String get privateKey => HEX.encode(_keyPairData!.bytes); + String get privateKey { + final privateKeyBytes = _keyPairData!.bytes; + + final publicKeyBytes = _keyPairData!.publicKey.bytes; + + final encodedBytes = privateKeyBytes + publicKeyBytes; + + final privateKey = base58encode(encodedBytes); + + return privateKey; + } Future init() async { final boxName = "${walletInfo.name.replaceAll(" ", "_")}_${SPLToken.boxName}"; @@ -135,8 +146,8 @@ abstract class SolanaWalletBase assert(mnemonic != null || privateKey != null); if (privateKey != null) { - final privateKeyBytes = HEX.decode(privateKey); - return await Wallet.fromPrivateKeyBytes(privateKey: privateKeyBytes); + final privateKeyBytes = base58decode(privateKey); + return await Wallet.fromPrivateKeyBytes(privateKey: privateKeyBytes.take(32).toList()); } return Wallet.fromMnemonic(mnemonic!, account: 0, change: 0); From dcfb2b2b730f27a849f0e866acba48517b821195 Mon Sep 17 00:00:00 2001 From: Matthew Fosse Date: Wed, 24 Apr 2024 17:00:53 -0700 Subject: [PATCH 05/17] fix empty string case (#1401) * bio auth mac fix * remove comment and change duration from 2 to 0 * cherry pick previous changes * fix empty string case * add support for path for all currency types * disable paths on electrum and monero nodes * undo mac auth changes * stuff I missed * 1 last thing * another thing I missed --- cw_bitcoin/pubspec.lock | 32 +++++++++----- cw_core/lib/node.dart | 6 +-- cw_core/pubspec.lock | 32 +++++++++----- cw_core/pubspec.yaml | 1 + cw_haven/pubspec.lock | 44 +++++++++++-------- cw_monero/example/pubspec.lock | 30 ++++++++----- cw_monero/pubspec.lock | 44 +++++++++++-------- cw_nano/pubspec.lock | 44 +++++++++++-------- lib/core/node_address_validator.dart | 6 ++- lib/entities/biometric_auth.dart | 2 +- lib/locales/yoruba_intl.dart | 2 +- lib/src/screens/nodes/widgets/node_form.dart | 26 ++++++----- .../validable_annotated_editable_text.dart | 2 +- lib/view_model/auth_view_model.dart | 2 +- .../node_create_or_edit_view_model.dart | 19 +++++++- 15 files changed, 182 insertions(+), 110 deletions(-) diff --git a/cw_bitcoin/pubspec.lock b/cw_bitcoin/pubspec.lock index 3d828243c..53cf550c8 100644 --- a/cw_bitcoin/pubspec.lock +++ b/cw_bitcoin/pubspec.lock @@ -217,10 +217,10 @@ packages: dependency: transitive description: name: collection - sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" + sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 url: "https://pub.dev" source: hosted - version: "1.17.1" + version: "1.17.2" convert: dependency: transitive description: @@ -434,18 +434,18 @@ packages: dependency: transitive description: name: matcher - sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" url: "https://pub.dev" source: hosted - version: "0.12.15" + version: "0.12.16" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "0.5.0" meta: dependency: transitive description: @@ -663,10 +663,10 @@ packages: dependency: transitive description: name: source_span - sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.10.0" stack_trace: dependency: transitive description: @@ -711,10 +711,10 @@ packages: dependency: transitive description: name: test_api - sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb + sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "0.6.0" timing: dependency: transitive description: @@ -748,13 +748,21 @@ packages: source: hosted version: "2.1.4" watcher: - dependency: transitive + dependency: "direct overridden" description: name: watcher sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" url: "https://pub.dev" source: hosted version: "1.1.0" + web: + dependency: transitive + description: + name: web + sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 + url: "https://pub.dev" + source: hosted + version: "0.1.4-beta" web_socket_channel: dependency: transitive description: @@ -788,5 +796,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.0.0 <4.0.0" + dart: ">=3.1.0-185.0.dev <4.0.0" flutter: ">=3.10.0" diff --git a/cw_core/lib/node.dart b/cw_core/lib/node.dart index d7e91d692..9d0806851 100644 --- a/cw_core/lib/node.dart +++ b/cw_core/lib/node.dart @@ -10,7 +10,7 @@ import 'package:http/io_client.dart' as ioc; part 'node.g.dart'; -Uri createUriFromElectrumAddress(String address) => Uri.tryParse('tcp://$address')!; +Uri createUriFromElectrumAddress(String address, String path) => Uri.tryParse('tcp://$address$path')!; @HiveType(typeId: Node.typeId) class Node extends HiveObject with Keyable { @@ -83,7 +83,7 @@ class Node extends HiveObject with Keyable { case WalletType.bitcoin: case WalletType.litecoin: case WalletType.bitcoinCash: - return createUriFromElectrumAddress(uriRaw); + return createUriFromElectrumAddress(uriRaw, path ?? ''); case WalletType.nano: case WalletType.banano: if (isSSL) { @@ -94,7 +94,7 @@ class Node extends HiveObject with Keyable { case WalletType.ethereum: case WalletType.polygon: case WalletType.solana: - return Uri.https(uriRaw, ''); + return Uri.https(uriRaw, path ?? ''); default: throw Exception('Unexpected type ${type.toString()} for Node uri'); } diff --git a/cw_core/pubspec.lock b/cw_core/pubspec.lock index 678e57b54..aef76f300 100644 --- a/cw_core/pubspec.lock +++ b/cw_core/pubspec.lock @@ -149,10 +149,10 @@ packages: dependency: transitive description: name: collection - sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" + sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 url: "https://pub.dev" source: hosted - version: "1.17.1" + version: "1.17.2" convert: dependency: transitive description: @@ -343,18 +343,18 @@ packages: dependency: transitive description: name: matcher - sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" url: "https://pub.dev" source: hosted - version: "0.12.15" + version: "0.12.16" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "0.5.0" meta: dependency: transitive description: @@ -564,10 +564,10 @@ packages: dependency: transitive description: name: source_span - sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.10.0" stack_trace: dependency: transitive description: @@ -612,10 +612,10 @@ packages: dependency: transitive description: name: test_api - sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb + sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "0.6.0" timing: dependency: transitive description: @@ -641,13 +641,21 @@ packages: source: hosted version: "2.1.4" watcher: - dependency: transitive + dependency: "direct overridden" description: name: watcher sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" url: "https://pub.dev" source: hosted version: "1.1.0" + web: + dependency: transitive + description: + name: web + sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 + url: "https://pub.dev" + source: hosted + version: "0.1.4-beta" web_socket_channel: dependency: transitive description: @@ -681,5 +689,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.0.0 <4.0.0" + dart: ">=3.1.0-185.0.dev <4.0.0" flutter: ">=3.10.0" diff --git a/cw_core/pubspec.yaml b/cw_core/pubspec.yaml index 04a840d4e..36fe9967e 100644 --- a/cw_core/pubspec.yaml +++ b/cw_core/pubspec.yaml @@ -33,6 +33,7 @@ dev_dependencies: mobx_codegen: ^2.0.7 hive_generator: ^2.0.1 + # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/cw_haven/pubspec.lock b/cw_haven/pubspec.lock index b0a350cc7..d84523539 100644 --- a/cw_haven/pubspec.lock +++ b/cw_haven/pubspec.lock @@ -69,10 +69,10 @@ packages: dependency: transitive description: name: build_daemon - sha256: "6bc5544ea6ce4428266e7ea680e945c68806c4aae2da0eb5e9ccf38df8d6acbf" + sha256: "5f02d73eb2ba16483e693f80bee4f088563a820e47d1027d4cdfe62b5bb43e65" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "4.0.0" build_resolvers: dependency: "direct dev" description: @@ -85,10 +85,10 @@ packages: dependency: "direct dev" description: name: build_runner - sha256: b0a8a7b8a76c493e85f1b84bffa0588859a06197863dba8c9036b15581fd9727 + sha256: "3ac61a79bfb6f6cc11f693591063a7f19a7af628dc52f141743edac5c16e8c22" url: "https://pub.dev" source: hosted - version: "2.3.3" + version: "2.4.9" build_runner_core: dependency: transitive description: @@ -149,10 +149,10 @@ packages: dependency: transitive description: name: collection - sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" + sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 url: "https://pub.dev" source: hosted - version: "1.17.1" + version: "1.17.2" convert: dependency: transitive description: @@ -350,18 +350,18 @@ packages: dependency: transitive description: name: matcher - sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" url: "https://pub.dev" source: hosted - version: "0.12.15" + version: "0.12.16" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "0.5.0" meta: dependency: transitive description: @@ -563,10 +563,10 @@ packages: dependency: transitive description: name: source_span - sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.10.0" stack_trace: dependency: transitive description: @@ -611,10 +611,10 @@ packages: dependency: transitive description: name: test_api - sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb + sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "0.6.0" timing: dependency: transitive description: @@ -640,13 +640,21 @@ packages: source: hosted version: "2.1.4" watcher: - dependency: transitive + dependency: "direct overridden" description: name: watcher - sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0" + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "1.1.0" + web: + dependency: transitive + description: + name: web + sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 + url: "https://pub.dev" + source: hosted + version: "0.1.4-beta" web_socket_channel: dependency: transitive description: @@ -680,5 +688,5 @@ packages: source: hosted version: "3.1.1" sdks: - dart: ">=3.0.0 <4.0.0" + dart: ">=3.1.0-185.0.dev <4.0.0" flutter: ">=3.7.0" diff --git a/cw_monero/example/pubspec.lock b/cw_monero/example/pubspec.lock index c9ca8d92b..ece0d4395 100644 --- a/cw_monero/example/pubspec.lock +++ b/cw_monero/example/pubspec.lock @@ -53,10 +53,10 @@ packages: dependency: transitive description: name: collection - sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" + sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 url: "https://pub.dev" source: hosted - version: "1.17.1" + version: "1.17.2" convert: dependency: transitive description: @@ -213,18 +213,18 @@ packages: dependency: transitive description: name: matcher - sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" url: "https://pub.dev" source: hosted - version: "0.12.15" + version: "0.12.16" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "0.5.0" meta: dependency: transitive description: @@ -354,10 +354,10 @@ packages: dependency: transitive description: name: source_span - sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.10.0" stack_trace: dependency: transitive description: @@ -394,10 +394,10 @@ packages: dependency: transitive description: name: test_api - sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb + sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "0.6.0" typed_data: dependency: transitive description: @@ -414,6 +414,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + web: + dependency: transitive + description: + name: web + sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 + url: "https://pub.dev" + source: hosted + version: "0.1.4-beta" win32: dependency: transitive description: @@ -431,5 +439,5 @@ packages: source: hosted version: "0.2.0+3" sdks: - dart: ">=3.0.6 <4.0.0" + dart: ">=3.1.0-185.0.dev <4.0.0" flutter: ">=3.7.0" diff --git a/cw_monero/pubspec.lock b/cw_monero/pubspec.lock index 0f8f2c90e..b736f80cb 100644 --- a/cw_monero/pubspec.lock +++ b/cw_monero/pubspec.lock @@ -69,10 +69,10 @@ packages: dependency: transitive description: name: build_daemon - sha256: "6bc5544ea6ce4428266e7ea680e945c68806c4aae2da0eb5e9ccf38df8d6acbf" + sha256: "5f02d73eb2ba16483e693f80bee4f088563a820e47d1027d4cdfe62b5bb43e65" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "4.0.0" build_resolvers: dependency: "direct dev" description: @@ -85,10 +85,10 @@ packages: dependency: "direct dev" description: name: build_runner - sha256: b0a8a7b8a76c493e85f1b84bffa0588859a06197863dba8c9036b15581fd9727 + sha256: "3ac61a79bfb6f6cc11f693591063a7f19a7af628dc52f141743edac5c16e8c22" url: "https://pub.dev" source: hosted - version: "2.3.3" + version: "2.4.9" build_runner_core: dependency: transitive description: @@ -149,10 +149,10 @@ packages: dependency: transitive description: name: collection - sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" + sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 url: "https://pub.dev" source: hosted - version: "1.17.1" + version: "1.17.2" convert: dependency: transitive description: @@ -366,18 +366,18 @@ packages: dependency: transitive description: name: matcher - sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" url: "https://pub.dev" source: hosted - version: "0.12.15" + version: "0.12.16" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "0.5.0" meta: dependency: transitive description: @@ -587,10 +587,10 @@ packages: dependency: transitive description: name: source_span - sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.10.0" stack_trace: dependency: transitive description: @@ -635,10 +635,10 @@ packages: dependency: transitive description: name: test_api - sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb + sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "0.6.0" timing: dependency: transitive description: @@ -664,13 +664,21 @@ packages: source: hosted version: "2.1.4" watcher: - dependency: transitive + dependency: "direct overridden" description: name: watcher - sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0" + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "1.1.0" + web: + dependency: transitive + description: + name: web + sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 + url: "https://pub.dev" + source: hosted + version: "0.1.4-beta" web_socket_channel: dependency: transitive description: @@ -704,5 +712,5 @@ packages: source: hosted version: "3.1.1" sdks: - dart: ">=3.0.6 <4.0.0" + dart: ">=3.1.0-185.0.dev <4.0.0" flutter: ">=3.7.0" diff --git a/cw_nano/pubspec.lock b/cw_nano/pubspec.lock index a42bb9ab4..0ebc5e75f 100644 --- a/cw_nano/pubspec.lock +++ b/cw_nano/pubspec.lock @@ -93,10 +93,10 @@ packages: dependency: transitive description: name: build_daemon - sha256: "757153e5d9cd88253cb13f28c2fb55a537dc31fefd98137549895b5beb7c6169" + sha256: "0343061a33da9c5810b2d6cee51945127d8f4c060b7fbdd9d54917f0a3feaaa1" url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "4.0.1" build_resolvers: dependency: transitive description: @@ -109,10 +109,10 @@ packages: dependency: "direct dev" description: name: build_runner - sha256: b0a8a7b8a76c493e85f1b84bffa0588859a06197863dba8c9036b15581fd9727 + sha256: "3ac61a79bfb6f6cc11f693591063a7f19a7af628dc52f141743edac5c16e8c22" url: "https://pub.dev" source: hosted - version: "2.3.3" + version: "2.4.9" build_runner_core: dependency: transitive description: @@ -173,10 +173,10 @@ packages: dependency: transitive description: name: collection - sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" + sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 url: "https://pub.dev" source: hosted - version: "1.17.1" + version: "1.17.2" convert: dependency: transitive description: @@ -419,18 +419,18 @@ packages: dependency: transitive description: name: matcher - sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" url: "https://pub.dev" source: hosted - version: "0.12.15" + version: "0.12.16" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "0.5.0" meta: dependency: transitive description: @@ -713,10 +713,10 @@ packages: dependency: transitive description: name: source_span - sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.10.0" stack_trace: dependency: transitive description: @@ -761,10 +761,10 @@ packages: dependency: transitive description: name: test_api - sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb + sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "0.6.0" timing: dependency: transitive description: @@ -790,13 +790,21 @@ packages: source: hosted version: "2.1.4" watcher: - dependency: transitive + dependency: "direct overridden" description: name: watcher - sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0" + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "1.1.0" + web: + dependency: transitive + description: + name: web + sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 + url: "https://pub.dev" + source: hosted + version: "0.1.4-beta" web_socket_channel: dependency: transitive description: @@ -830,5 +838,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.0.0 <4.0.0" + dart: ">=3.1.0-185.0.dev <4.0.0" flutter: ">=3.7.0" diff --git a/lib/core/node_address_validator.dart b/lib/core/node_address_validator.dart index c1fe4ba91..0c8a0c37c 100644 --- a/lib/core/node_address_validator.dart +++ b/lib/core/node_address_validator.dart @@ -11,5 +11,9 @@ class NodeAddressValidator extends TextValidator { class NodePathValidator extends TextValidator { NodePathValidator() - : super(errorMessage: S.current.error_text_node_address, pattern: '^([/0-9a-zA-Z.\-]+)?\$'); + : super( + errorMessage: S.current.error_text_node_address, + pattern: '^([/0-9a-zA-Z.\-]+)?\$', + isAutovalidate: true, + ); } diff --git a/lib/entities/biometric_auth.dart b/lib/entities/biometric_auth.dart index febbfa469..4b2bfd906 100644 --- a/lib/entities/biometric_auth.dart +++ b/lib/entities/biometric_auth.dart @@ -29,4 +29,4 @@ class BiometricAuth { return false; } -} +} \ No newline at end of file diff --git a/lib/locales/yoruba_intl.dart b/lib/locales/yoruba_intl.dart index 889c21cb7..f16188529 100644 --- a/lib/locales/yoruba_intl.dart +++ b/lib/locales/yoruba_intl.dart @@ -955,4 +955,4 @@ String get todayLabel => 'Oyọ'; @override String get noSpellCheckReplacementsLabel => ""; -} +} \ No newline at end of file diff --git a/lib/src/screens/nodes/widgets/node_form.dart b/lib/src/screens/nodes/widgets/node_form.dart index e8c4b0ab3..74daa41cc 100644 --- a/lib/src/screens/nodes/widgets/node_form.dart +++ b/lib/src/screens/nodes/widgets/node_form.dart @@ -96,18 +96,20 @@ class NodeForm extends StatelessWidget { ], ), SizedBox(height: 10.0), - Row( - children: [ - Expanded( - child: BaseTextFormField( - controller: _pathController, - hintText: "/path", - validator: NodePathValidator(), - ), - ) - ], - ), - SizedBox(height: 10.0), + if (nodeViewModel.hasPathSupport) ...[ + Row( + children: [ + Expanded( + child: BaseTextFormField( + controller: _pathController, + hintText: "/path", + validator: NodePathValidator(), + ), + ) + ], + ), + SizedBox(height: 10.0), + ], Row( children: [ Expanded( diff --git a/lib/src/widgets/validable_annotated_editable_text.dart b/lib/src/widgets/validable_annotated_editable_text.dart index 6c3fc4f16..16ccc76f6 100644 --- a/lib/src/widgets/validable_annotated_editable_text.dart +++ b/lib/src/widgets/validable_annotated_editable_text.dart @@ -167,4 +167,4 @@ class ValidatableAnnotatedEditableTextState extends EditableTextState { return TextSpan(style: widget.style, text: text); } -} +} \ No newline at end of file diff --git a/lib/view_model/auth_view_model.dart b/lib/view_model/auth_view_model.dart index e50f4db0c..4fb93cfea 100644 --- a/lib/view_model/auth_view_model.dart +++ b/lib/view_model/auth_view_model.dart @@ -125,4 +125,4 @@ abstract class AuthViewModelBase with Store { _authService.saveLastAuthTime(); } } -} +} \ No newline at end of file diff --git a/lib/view_model/node_list/node_create_or_edit_view_model.dart b/lib/view_model/node_list/node_create_or_edit_view_model.dart index 283a32cbf..7fe3d1c98 100644 --- a/lib/view_model/node_list/node_create_or_edit_view_model.dart +++ b/lib/view_model/node_list/node_create_or_edit_view_model.dart @@ -69,6 +69,24 @@ abstract class NodeCreateOrEditViewModelBase with Store { bool get hasTestnetSupport => _walletType == WalletType.bitcoin; + bool get hasPathSupport { + switch (_walletType) { + case WalletType.ethereum: + case WalletType.polygon: + case WalletType.solana: + case WalletType.banano: + case WalletType.nano: + return true; + case WalletType.none: + case WalletType.monero: + case WalletType.haven: + case WalletType.litecoin: + case WalletType.bitcoinCash: + case WalletType.bitcoin: + return false; + } + } + String get uri { var uri = address; @@ -217,7 +235,6 @@ abstract class NodeCreateOrEditViewModelBase with Store { final port = uri.port.toString(); final path = uri.path; - setAddress(ipAddress); setPath(path); setPassword(rpcPassword); From 2ac81250c24ebe84610242ac62591a3e063d974f Mon Sep 17 00:00:00 2001 From: Adegoke David <64401859+Blazebrain@users.noreply.github.com> Date: Thu, 25 Apr 2024 02:14:11 +0100 Subject: [PATCH 06/17] CW-615-Add-Check-For-Contract-Address (#1387) * feat: Check if address is a valid Externally Owned Address * feat: Check if the EVM address received when exchanging tokens is a valid EOA address * move the contract address check to be only in the case of ThorChain [skip ci] * some enhancements * feat: Implement check for contract address for inputAddress when exchanging to ETH * fix: Remove previous implementation and clean up current implementation for the check for contract address * chore: Remove unneed space * chore: Remove unneed space --------- Co-authored-by: OmarHatem --- lib/core/create_trade_result.dart | 9 ++ .../exchange/exchange_view_model.dart | 120 +++++++++++++++--- lib/view_model/send/send_view_model.dart | 6 +- res/values/strings_ar.arb | 1 + res/values/strings_bg.arb | 1 + res/values/strings_cs.arb | 1 + res/values/strings_de.arb | 1 + res/values/strings_en.arb | 1 + res/values/strings_es.arb | 1 + res/values/strings_fr.arb | 1 + res/values/strings_ha.arb | 1 + res/values/strings_hi.arb | 1 + res/values/strings_hr.arb | 1 + res/values/strings_id.arb | 1 + res/values/strings_it.arb | 1 + res/values/strings_ja.arb | 1 + res/values/strings_ko.arb | 1 + res/values/strings_my.arb | 1 + res/values/strings_nl.arb | 1 + res/values/strings_pl.arb | 1 + res/values/strings_pt.arb | 1 + res/values/strings_ru.arb | 1 + res/values/strings_th.arb | 1 + res/values/strings_tl.arb | 1 + res/values/strings_tr.arb | 1 + res/values/strings_uk.arb | 1 + res/values/strings_ur.arb | 1 + res/values/strings_yo.arb | 1 + res/values/strings_zh.arb | 1 + tool/configure.dart | 3 +- 30 files changed, 146 insertions(+), 18 deletions(-) create mode 100644 lib/core/create_trade_result.dart diff --git a/lib/core/create_trade_result.dart b/lib/core/create_trade_result.dart new file mode 100644 index 000000000..0e873d51e --- /dev/null +++ b/lib/core/create_trade_result.dart @@ -0,0 +1,9 @@ +class CreateTradeResult { + bool result; + String? errorMessage; + + CreateTradeResult({ + required this.result, + this.errorMessage, + }); +} diff --git a/lib/view_model/exchange/exchange_view_model.dart b/lib/view_model/exchange/exchange_view_model.dart index eba347ac4..4e5902faa 100644 --- a/lib/view_model/exchange/exchange_view_model.dart +++ b/lib/view_model/exchange/exchange_view_model.dart @@ -3,8 +3,20 @@ import 'dart:collection'; import 'dart:convert'; import 'package:bitcoin_base/bitcoin_base.dart'; -import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart'; +import 'package:cake_wallet/core/create_trade_result.dart'; +import 'package:cw_core/crypto_currency.dart'; +import 'package:cw_core/sync_status.dart'; +import 'package:cw_core/transaction_priority.dart'; +import 'package:cw_core/wallet_type.dart'; +import 'package:hive/hive.dart'; +import 'package:http/http.dart' as http; +import 'package:intl/intl.dart'; +import 'package:mobx/mobx.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import 'package:cake_wallet/.secrets.g.dart' as secrets; import 'package:cake_wallet/bitcoin/bitcoin.dart'; +import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart'; import 'package:cake_wallet/core/wallet_change_listener_view_model.dart'; import 'package:cake_wallet/entities/exchange_api_mode.dart'; import 'package:cake_wallet/entities/preferences_key.dart'; @@ -33,14 +45,6 @@ import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/store/templates/exchange_template_store.dart'; import 'package:cake_wallet/utils/feature_flag.dart'; import 'package:cake_wallet/view_model/contact_list/contact_list_view_model.dart'; -import 'package:cw_core/crypto_currency.dart'; -import 'package:cw_core/sync_status.dart'; -import 'package:cw_core/transaction_priority.dart'; -import 'package:cw_core/wallet_type.dart'; -import 'package:hive/hive.dart'; -import 'package:intl/intl.dart'; -import 'package:mobx/mobx.dart'; -import 'package:shared_preferences/shared_preferences.dart'; part 'exchange_view_model.g.dart'; @@ -516,10 +520,12 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with trade.walletId = wallet.id; trade.fromWalletAddress = wallet.walletAddresses.address; - if (!isCanCreateTrade(trade)) { + final canCreateTrade = await isCanCreateTrade(trade); + if (!canCreateTrade.result) { tradeState = TradeIsCreatedFailure( - title: S.current.trade_not_created, - error: S.current.thorchain_taproot_address_not_supported); + title: S.current.trade_not_created, + error: canCreateTrade.errorMessage ?? '', + ); return; } @@ -776,16 +782,100 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with int get receiveMaxDigits => receiveCurrency.decimals; - bool isCanCreateTrade(Trade trade) { + Future isCanCreateTrade(Trade trade) async { if (trade.provider == ExchangeProviderDescription.thorChain) { final payoutAddress = trade.payoutAddress ?? ''; final fromWalletAddress = trade.fromWalletAddress ?? ''; final tapRootPattern = RegExp(P2trAddress.regex.pattern); if (tapRootPattern.hasMatch(payoutAddress) || tapRootPattern.hasMatch(fromWalletAddress)) { - return false; + return CreateTradeResult( + result: false, + errorMessage: S.current.thorchain_taproot_address_not_supported, + ); + } + + final currenciesToCheckPattern = RegExp('0x[0-9a-zA-Z]'); + + // Perform checks for payOutAddress + final isPayOutAddressAccordingToPattern = currenciesToCheckPattern.hasMatch(payoutAddress); + + if (isPayOutAddressAccordingToPattern) { + final isPayOutAddressEOA = await _isExternallyOwnedAccountAddress(payoutAddress); + + return CreateTradeResult( + result: isPayOutAddressEOA, + errorMessage: + !isPayOutAddressEOA ? S.current.thorchain_contract_address_not_supported : null, + ); + } + + // Perform checks for fromWalletAddress + final isFromWalletAddressAddressAccordingToPattern = + currenciesToCheckPattern.hasMatch(fromWalletAddress); + + if (isFromWalletAddressAddressAccordingToPattern) { + final isFromWalletAddressEOA = await _isExternallyOwnedAccountAddress(fromWalletAddress); + + return CreateTradeResult( + result: isFromWalletAddressEOA, + errorMessage: + !isFromWalletAddressEOA ? S.current.thorchain_contract_address_not_supported : null, + ); } } - return true; + return CreateTradeResult(result: true); + } + + String _normalizeReceiveCurrency(CryptoCurrency receiveCurrency) { + switch (receiveCurrency) { + case CryptoCurrency.eth: + return 'eth'; + case CryptoCurrency.maticpoly: + return 'polygon'; + default: + return receiveCurrency.tag ?? ''; + } + } + + Future _isExternallyOwnedAccountAddress(String receivingAddress) async { + final normalizedReceiveCurrency = _normalizeReceiveCurrency(receiveCurrency); + + final isEOAAddress = !(await _isContractAddress(normalizedReceiveCurrency, receivingAddress)); + return isEOAAddress; + } + + Future _isContractAddress(String chainName, String contractAddress) async { + final httpClient = http.Client(); + + final uri = Uri.https( + 'deep-index.moralis.io', + '/api/v2.2/erc20/metadata', + { + "chain": chainName, + "addresses": contractAddress, + }, + ); + + try { + final response = await httpClient.get( + uri, + headers: { + "Accept": "application/json", + "X-API-Key": secrets.moralisApiKey, + }, + ); + + final decodedResponse = jsonDecode(response.body)[0] as Map; + + final name = decodedResponse['name'] as String?; + + bool isContractAddress = name!.isNotEmpty; + + return isContractAddress; + } catch (e) { + print(e); + return false; + } } } diff --git a/lib/view_model/send/send_view_model.dart b/lib/view_model/send/send_view_model.dart index 038301db4..298cc3eed 100644 --- a/lib/view_model/send/send_view_model.dart +++ b/lib/view_model/send/send_view_model.dart @@ -324,14 +324,16 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor Future createTransaction({ExchangeProvider? provider}) async { try { state = IsExecutingState(); + pendingTransaction = await wallet.createTransaction(_credentials()); if (provider is ThorChainExchangeProvider) { final outputCount = pendingTransaction?.outputCount ?? 0; if (outputCount > 10) { - throw Exception("ThorChain does not support more than 10 outputs"); + throw Exception("THORChain does not support more than 10 outputs"); } + if (_hasTaprootInput(pendingTransaction)) { - throw Exception("ThorChain does not support Taproot addresses"); + throw Exception("THORChain does not support Taproot addresses"); } } state = ExecutedSuccessfullyState(); diff --git a/res/values/strings_ar.arb b/res/values/strings_ar.arb index 15b9712fc..cf9959f17 100644 --- a/res/values/strings_ar.arb +++ b/res/values/strings_ar.arb @@ -660,6 +660,7 @@ "template_name": "اسم القالب", "third_intro_content": "يعيش Yats خارج Cake Wallet أيضًا. يمكن استبدال أي عنوان محفظة على وجه الأرض بـ Yat!", "third_intro_title": "يتماشي Yat بلطف مع الآخرين", + "thorchain_contract_address_not_supported": "لا يدعم Thorchain الإرسال إلى عنوان العقد", "thorchain_taproot_address_not_supported": "لا يدعم مزود Thorchain عناوين Taproot. يرجى تغيير العنوان أو تحديد مزود مختلف.", "time": "${minutes}د ${seconds}س", "tip": "بقشيش:", diff --git a/res/values/strings_bg.arb b/res/values/strings_bg.arb index d479bd57d..bd1cd645d 100644 --- a/res/values/strings_bg.arb +++ b/res/values/strings_bg.arb @@ -660,6 +660,7 @@ "template_name": "Име на шаблон", "third_intro_content": "Yats също живее извън Cake Wallet. Всеки адрес на портфейл може да бъде заменен с Yat!", "third_intro_title": "Yat добре се сработва с други", + "thorchain_contract_address_not_supported": "Thorchain не подкрепя изпращането до адрес на договор", "thorchain_taproot_address_not_supported": "Доставчикът на Thorchain не поддържа адреси на TapRoot. Моля, променете адреса или изберете друг доставчик.", "time": "${minutes} мин ${seconds} сек", "tip": "Tip:", diff --git a/res/values/strings_cs.arb b/res/values/strings_cs.arb index 547c926af..4d3458bec 100644 --- a/res/values/strings_cs.arb +++ b/res/values/strings_cs.arb @@ -660,6 +660,7 @@ "template_name": "Název šablony", "third_intro_content": "Yat existuje i mimo Cake Wallet. Jakákoliv adresa peněženky na světě může být nahrazena Yatem!", "third_intro_title": "Yat dobře spolupracuje s ostatními", + "thorchain_contract_address_not_supported": "Thorchain nepodporuje odeslání na adresu smlouvy", "thorchain_taproot_address_not_supported": "Poskytovatel Thorchain nepodporuje adresy Taproot. Změňte adresu nebo vyberte jiného poskytovatele.", "time": "${minutes}m ${seconds}s", "tip": "Spropitné:", diff --git a/res/values/strings_de.arb b/res/values/strings_de.arb index 97f2ccdc2..7efb0b682 100644 --- a/res/values/strings_de.arb +++ b/res/values/strings_de.arb @@ -661,6 +661,7 @@ "template_name": "Vorlagenname", "third_intro_content": "Yats leben auch außerhalb von Cake Wallet. Jede Wallet-Adresse auf der Welt kann durch ein Yat ersetzt werden!", "third_intro_title": "Yat spielt gut mit anderen", + "thorchain_contract_address_not_supported": "Thorchain unterstützt das Senden an eine Vertragsadresse nicht", "thorchain_taproot_address_not_supported": "Der Thorchain -Anbieter unterstützt keine Taproot -Adressen. Bitte ändern Sie die Adresse oder wählen Sie einen anderen Anbieter aus.", "time": "${minutes}m ${seconds}s", "tip": "Hinweis:", diff --git a/res/values/strings_en.arb b/res/values/strings_en.arb index 60de404fd..8f8b753d6 100644 --- a/res/values/strings_en.arb +++ b/res/values/strings_en.arb @@ -660,6 +660,7 @@ "template_name": "Template Name", "third_intro_content": "Yats live outside of Cake Wallet, too. Any wallet address on earth can be replaced with a Yat!", "third_intro_title": "Yat plays nicely with others", + "thorchain_contract_address_not_supported": "THORChain does not support sending to a contract address", "thorchain_taproot_address_not_supported": "The ThorChain provider does not support Taproot addresses. Please change the address or select a different provider.", "time": "${minutes}m ${seconds}s", "tip": "Tip:", diff --git a/res/values/strings_es.arb b/res/values/strings_es.arb index 60cac3a8c..7de9cff53 100644 --- a/res/values/strings_es.arb +++ b/res/values/strings_es.arb @@ -661,6 +661,7 @@ "template_name": "Nombre de la plantilla", "third_intro_content": "Los Yats también viven fuera de Cake Wallet. Cualquier dirección de billetera en la tierra se puede reemplazar con un Yat!", "third_intro_title": "Yat juega muy bien con otras", + "thorchain_contract_address_not_supported": "Thorchain no admite enviar a una dirección de contrato", "thorchain_taproot_address_not_supported": "El proveedor de Thorchain no admite las direcciones de Taproot. Cambie la dirección o seleccione un proveedor diferente.", "time": "${minutes}m ${seconds}s", "tip": "Consejo:", diff --git a/res/values/strings_fr.arb b/res/values/strings_fr.arb index 691c481c1..2c76122fc 100644 --- a/res/values/strings_fr.arb +++ b/res/values/strings_fr.arb @@ -660,6 +660,7 @@ "template_name": "Nom du modèle", "third_intro_content": "Les Yats existent aussi en dehors de Cake Wallet. Toute adresse sur terre peut être remplacée par un Yat !", "third_intro_title": "Yat est universel", + "thorchain_contract_address_not_supported": "Thorchain ne prend pas en charge l'envoi à une adresse de contrat", "thorchain_taproot_address_not_supported": "Le fournisseur de Thorchain ne prend pas en charge les adresses de tapoot. Veuillez modifier l'adresse ou sélectionner un autre fournisseur.", "time": "${minutes}m ${seconds}s", "tip": "Pourboire :", diff --git a/res/values/strings_ha.arb b/res/values/strings_ha.arb index f310f67f3..bac970207 100644 --- a/res/values/strings_ha.arb +++ b/res/values/strings_ha.arb @@ -662,6 +662,7 @@ "template_name": "Sunan Samfura", "third_intro_content": "Yats suna zaune a wajen Kek Wallet, kuma. Ana iya maye gurbin kowane adireshin walat a duniya da Yat!", "third_intro_title": "Yat yana wasa da kyau tare da wasu", + "thorchain_contract_address_not_supported": "Thorchain baya goyon bayan aika zuwa adireshin kwangila", "thorchain_taproot_address_not_supported": "Mai ba da tallafi na ThorChain baya goyan bayan adreshin taproot. Da fatan za a canza adireshin ko zaɓi mai bayarwa daban.", "time": "${minutes}m ${seconds}s", "tip": "Tukwici:", diff --git a/res/values/strings_hi.arb b/res/values/strings_hi.arb index 671c7a765..5a9706bd5 100644 --- a/res/values/strings_hi.arb +++ b/res/values/strings_hi.arb @@ -662,6 +662,7 @@ "template_name": "टेम्पलेट नाम", "third_intro_content": "Yats Cake Wallet के बाहर भी रहता है। धरती पर किसी भी वॉलेट पते को Yat से बदला जा सकता है!", "third_intro_title": "Yat दूसरों के साथ अच्छा खेलता है", + "thorchain_contract_address_not_supported": "थोरचेन एक अनुबंध पते पर भेजने का समर्थन नहीं करता है", "thorchain_taproot_address_not_supported": "थोरचेन प्रदाता टैपरोट पते का समर्थन नहीं करता है। कृपया पता बदलें या एक अलग प्रदाता का चयन करें।", "time": "${minutes}m ${seconds}s", "tip": "टिप:", diff --git a/res/values/strings_hr.arb b/res/values/strings_hr.arb index 67e25d59a..94f675a1d 100644 --- a/res/values/strings_hr.arb +++ b/res/values/strings_hr.arb @@ -660,6 +660,7 @@ "template_name": "Naziv predloška", "third_intro_content": "Yats žive i izvan Cake Wallet -a. Bilo koja adresa novčanika na svijetu može se zamijeniti Yat!", "third_intro_title": "Yat se lijepo igra s drugima", + "thorchain_contract_address_not_supported": "Thorchain ne podržava slanje na adresu ugovora", "thorchain_taproot_address_not_supported": "Thorchain pružatelj ne podržava Taproot adrese. Promijenite adresu ili odaberite drugog davatelja usluga.", "time": "${minutes}m ${seconds}s", "tip": "Savjet:", diff --git a/res/values/strings_id.arb b/res/values/strings_id.arb index cca6f9b2a..69e270d10 100644 --- a/res/values/strings_id.arb +++ b/res/values/strings_id.arb @@ -663,6 +663,7 @@ "template_name": "Nama Templat", "third_intro_content": "Yats hidup di luar Cake Wallet juga. Setiap alamat dompet di dunia dapat diganti dengan Yat!", "third_intro_title": "Yat bermain baik dengan yang lain", + "thorchain_contract_address_not_supported": "Thorchain tidak mendukung pengiriman ke alamat kontrak", "thorchain_taproot_address_not_supported": "Penyedia Thorchain tidak mendukung alamat Taproot. Harap ubah alamatnya atau pilih penyedia yang berbeda.", "time": "${minutes}m ${seconds}s", "tip": "Tip:", diff --git a/res/values/strings_it.arb b/res/values/strings_it.arb index 4e04c0498..09b3e43bb 100644 --- a/res/values/strings_it.arb +++ b/res/values/strings_it.arb @@ -662,6 +662,7 @@ "template_name": "Nome modello", "third_intro_content": "Yat può funzionare anche fuori da Cake Wallet. Qualsiasi indirizzo di portafoglio sulla terra può essere sostituito con uno Yat!", "third_intro_title": "Yat gioca bene con gli altri", + "thorchain_contract_address_not_supported": "Thorchain non supporta l'invio a un indirizzo contrattuale", "thorchain_taproot_address_not_supported": "Il provider di Thorchain non supporta gli indirizzi di TapRoot. Si prega di modificare l'indirizzo o selezionare un fornitore diverso.", "time": "${minutes}m ${seconds}s", "tip": "Suggerimento:", diff --git a/res/values/strings_ja.arb b/res/values/strings_ja.arb index b3aa527d6..b067c2721 100644 --- a/res/values/strings_ja.arb +++ b/res/values/strings_ja.arb @@ -661,6 +661,7 @@ "template_name": "テンプレート名", "third_intro_content": "YatsはCakeWalletの外にも住んでいます。 地球上のどのウォレットアドレスもYatに置き換えることができます!", "third_intro_title": "Yatは他の人とうまく遊ぶ", + "thorchain_contract_address_not_supported": "Thorchainは、契約アドレスへの送信をサポートしていません", "thorchain_taproot_address_not_supported": "Thorchainプロバイダーは、TapRootアドレスをサポートしていません。アドレスを変更するか、別のプロバイダーを選択してください。", "time": "${minutes}m ${seconds}s", "tip": "ヒント: ", diff --git a/res/values/strings_ko.arb b/res/values/strings_ko.arb index 6c5800614..d9881ad04 100644 --- a/res/values/strings_ko.arb +++ b/res/values/strings_ko.arb @@ -661,6 +661,7 @@ "template_name": "템플릿 이름", "third_intro_content": "Yats는 Cake Wallet 밖에서도 살고 있습니다. 지구상의 모든 지갑 주소는 Yat!", "third_intro_title": "Yat는 다른 사람들과 잘 놉니다.", + "thorchain_contract_address_not_supported": "Thorchain은 계약 주소로 보내는 것을 지원하지 않습니다", "thorchain_taproot_address_not_supported": "Thorchain 제공 업체는 Taproot 주소를 지원하지 않습니다. 주소를 변경하거나 다른 공급자를 선택하십시오.", "time": "${minutes}m ${seconds}s", "tip": "팁:", diff --git a/res/values/strings_my.arb b/res/values/strings_my.arb index 96f141eae..c36f63414 100644 --- a/res/values/strings_my.arb +++ b/res/values/strings_my.arb @@ -660,6 +660,7 @@ "template_name": "နမူနာပုံစံ", "third_intro_content": "Yats သည် Cake Wallet အပြင်ဘက်တွင် နေထိုင်ပါသည်။ ကမ္ဘာပေါ်ရှိ မည်သည့်ပိုက်ဆံအိတ်လိပ်စာကို Yat ဖြင့် အစားထိုးနိုင်ပါသည်။", "third_intro_title": "Yat သည် အခြားသူများနှင့် ကောင်းစွာကစားသည်။", + "thorchain_contract_address_not_supported": "Thorchain သည်စာချုပ်လိပ်စာသို့ပို့ခြင်းမပြုပါ", "thorchain_taproot_address_not_supported": "Thorchain Provider သည် Taproot လိပ်စာများကိုမထောက်ခံပါ။ ကျေးဇူးပြု. လိပ်စာကိုပြောင်းပါသို့မဟုတ်အခြားပံ့ပိုးပေးသူကိုရွေးချယ်ပါ။", "time": "${minutes}m ${seconds}s", "tip": "အကြံပြုချက်-", diff --git a/res/values/strings_nl.arb b/res/values/strings_nl.arb index 1ce17f706..f258b8f62 100644 --- a/res/values/strings_nl.arb +++ b/res/values/strings_nl.arb @@ -660,6 +660,7 @@ "template_name": "Sjabloonnaam", "third_intro_content": "Yats wonen ook buiten Cake Wallet. Elk portemonnee-adres op aarde kan worden vervangen door een Yat!", "third_intro_title": "Yat speelt leuk met anderen", + "thorchain_contract_address_not_supported": "Thorchain ondersteunt het verzenden niet naar een contractadres", "thorchain_taproot_address_not_supported": "De Thorchain -provider ondersteunt geen Taprooot -adressen. Wijzig het adres of selecteer een andere provider.", "time": "${minutes}m ${seconds}s", "tip": "Tip:", diff --git a/res/values/strings_pl.arb b/res/values/strings_pl.arb index f48ad5dde..4627d0242 100644 --- a/res/values/strings_pl.arb +++ b/res/values/strings_pl.arb @@ -660,6 +660,7 @@ "template_name": "Nazwa szablonu", "third_intro_content": "Yats mieszkają również poza Cake Wallet. Każdy adres portfela na ziemi można zastąpić Yat!", "third_intro_title": "Yat ładnie bawi się z innymi", + "thorchain_contract_address_not_supported": "Thorchain nie wspiera wysyłania na adres umowy", "thorchain_taproot_address_not_supported": "Dostawca Thorchain nie obsługuje adresów TAPROOT. Zmień adres lub wybierz innego dostawcę.", "time": "${minutes}m ${seconds}s", "tip": "wskazówka:", diff --git a/res/values/strings_pt.arb b/res/values/strings_pt.arb index 15cc9f01e..2a781c76b 100644 --- a/res/values/strings_pt.arb +++ b/res/values/strings_pt.arb @@ -662,6 +662,7 @@ "template_name": "Nome do modelo", "third_intro_content": "Yats também mora fora da Cake Wallet. Qualquer endereço de carteira na Terra pode ser substituído por um Yat!", "third_intro_title": "Yat joga bem com os outros", + "thorchain_contract_address_not_supported": "Thorchain não suporta o envio para um endereço de contrato", "thorchain_taproot_address_not_supported": "O provedor de Thorchain não suporta endereços de raiz de Tap. Altere o endereço ou selecione um provedor diferente.", "time": "${minutes}m ${seconds}s", "tip": "Dica:", diff --git a/res/values/strings_ru.arb b/res/values/strings_ru.arb index ac0fac2ba..22bac3e33 100644 --- a/res/values/strings_ru.arb +++ b/res/values/strings_ru.arb @@ -661,6 +661,7 @@ "template_name": "Имя Шаблона", "third_intro_content": "Yat находятся за пределами Cake Wallet. Любой адрес кошелька на земле можно заменить на Yat!", "third_intro_title": "Yat хорошо взаимодействует с другими", + "thorchain_contract_address_not_supported": "Thorchain не поддерживает отправку на адрес контракта", "thorchain_taproot_address_not_supported": "Поставщик Thorchain не поддерживает адреса taproot. Пожалуйста, измените адрес или выберите другого поставщика.", "time": "${minutes}мин ${seconds}сек", "tip": "Совет:", diff --git a/res/values/strings_th.arb b/res/values/strings_th.arb index 7030f6f7f..c0f58495c 100644 --- a/res/values/strings_th.arb +++ b/res/values/strings_th.arb @@ -660,6 +660,7 @@ "template_name": "ชื่อแม่แบบ", "third_intro_content": "Yat อาศัยอยู่นอก Cake Wallet ด้วย ที่อยู่กระเป๋าใดๆ ทั่วโลกสามารถแทนด้วย Yat ได้อีกด้วย!", "third_intro_title": "Yat ปฏิบัติตนอย่างดีกับผู้อื่น", + "thorchain_contract_address_not_supported": "Thorchain ไม่สนับสนุนการส่งไปยังที่อยู่สัญญา", "thorchain_taproot_address_not_supported": "ผู้ให้บริการ Thorchain ไม่รองรับที่อยู่ taproot โปรดเปลี่ยนที่อยู่หรือเลือกผู้ให้บริการอื่น", "time": "${minutes}m ${seconds}s", "tip": "เพิ่มค่าตอบแทน:", diff --git a/res/values/strings_tl.arb b/res/values/strings_tl.arb index 05a363bac..8c3b13b3b 100644 --- a/res/values/strings_tl.arb +++ b/res/values/strings_tl.arb @@ -660,6 +660,7 @@ "template_name": "Pangalan ng Template", "third_intro_content": "Ang mga yats ay nakatira sa labas ng cake wallet, din. Ang anumang address ng pitaka sa mundo ay maaaring mapalitan ng isang yat!", "third_intro_title": "Si Yat ay mahusay na gumaganap sa iba", + "thorchain_contract_address_not_supported": "Hindi sinusuportahan ng Thorchain ang pagpapadala sa isang address ng kontrata", "thorchain_taproot_address_not_supported": "Ang Tagabigay ng Thorchain ay hindi sumusuporta sa mga address ng taproot. Mangyaring baguhin ang address o pumili ng ibang provider.", "time": "${minutes} m ${seconds} s", "tip": "Tip:", diff --git a/res/values/strings_tr.arb b/res/values/strings_tr.arb index ce342df2f..534a36c77 100644 --- a/res/values/strings_tr.arb +++ b/res/values/strings_tr.arb @@ -660,6 +660,7 @@ "template_name": "şablon adı", "third_intro_content": "Yat'lar Cake Wallet'ın dışında da çalışabilir. Dünya üzerindeki herhangi bir cüzdan adresi Yat ile değiştirilebilir!", "third_intro_title": "Yat diğerleriyle iyi çalışır", + "thorchain_contract_address_not_supported": "Thorchain bir sözleşme adresine göndermeyi desteklemiyor", "thorchain_taproot_address_not_supported": "Thorchain sağlayıcısı Taproot adreslerini desteklemiyor. Lütfen adresi değiştirin veya farklı bir sağlayıcı seçin.", "time": "${minutes}d ${seconds}s", "tip": "Bahşiş:", diff --git a/res/values/strings_uk.arb b/res/values/strings_uk.arb index 4afd47fe2..5d1e2be05 100644 --- a/res/values/strings_uk.arb +++ b/res/values/strings_uk.arb @@ -661,6 +661,7 @@ "template_name": "Назва шаблону", "third_intro_content": "Yat знаходиться за межами Cake Wallet. Будь-яку адресу гаманця на землі можна замінити на Yat!", "third_intro_title": "Yat добре взаємодіє з іншими", + "thorchain_contract_address_not_supported": "Thorchain не підтримує надсилання на адресу контракту", "thorchain_taproot_address_not_supported": "Постачальник Thorchain не підтримує адреси Taproot. Будь ласка, змініть адресу або виберіть іншого постачальника.", "time": "${minutes}хв ${seconds}сек", "tip": "Порада:", diff --git a/res/values/strings_ur.arb b/res/values/strings_ur.arb index fac066ace..d98a85753 100644 --- a/res/values/strings_ur.arb +++ b/res/values/strings_ur.arb @@ -662,6 +662,7 @@ "template_name": "ٹیمپلیٹ کا نام", "third_intro_content": "Yats بھی Cake والیٹ سے باہر رہتے ہیں۔ زمین پر کسی بھی بٹوے کے پتے کو Yat سے تبدیل کیا جا سکتا ہے!", "third_intro_title": "Yat دوسروں کے ساتھ اچھی طرح کھیلتا ہے۔", + "thorchain_contract_address_not_supported": "تھورچین معاہدے کے پتے بھیجنے کی حمایت نہیں کرتا ہے", "thorchain_taproot_address_not_supported": "تھورچین فراہم کنندہ ٹیپروٹ پتے کی حمایت نہیں کرتا ہے۔ براہ کرم پتہ تبدیل کریں یا ایک مختلف فراہم کنندہ کو منتخب کریں۔", "time": "${minutes}m ${seconds}s", "tip": "ٹپ:", diff --git a/res/values/strings_yo.arb b/res/values/strings_yo.arb index 1f131f3d9..faaeb8837 100644 --- a/res/values/strings_yo.arb +++ b/res/values/strings_yo.arb @@ -661,6 +661,7 @@ "template_name": "Orukọ Awoṣe", "third_intro_content": "A sì lè lo Yats níta Cake Wallet. A lè rọ́pò Àdírẹ́sì kankan àpamọ́wọ́ fún Yat!", "third_intro_title": "Àlàáfíà ni Yat àti àwọn ìmíìn jọ wà", + "thorchain_contract_address_not_supported": "Thorchain ko ṣe atilẹyin fifiranṣẹ si adirẹsi adehun kan", "thorchain_taproot_address_not_supported": "Olupese Trockchain ko ṣe atilẹyin awọn adirẹsi Taproot. Jọwọ yi adirẹsi pada tabi yan olupese ti o yatọ.", "time": "${minutes}ìṣj ${seconds}ìṣs", "tip": "Owó àfikún:", diff --git a/res/values/strings_zh.arb b/res/values/strings_zh.arb index 10d11b2c0..2d5251d86 100644 --- a/res/values/strings_zh.arb +++ b/res/values/strings_zh.arb @@ -660,6 +660,7 @@ "template_name": "模板名称", "third_intro_content": "Yats 也住在 Cake Wallet 之外。 地球上任何一個錢包地址都可以用一個Yat來代替!", "third_intro_title": "Yat 和別人玩得很好", + "thorchain_contract_address_not_supported": "Thorchain不支持发送到合同地址", "thorchain_taproot_address_not_supported": "Thorchain提供商不支持Taproot地址。请更改地址或选择其他提供商。", "time": "${minutes}m ${seconds}s", "tip": "提示:", diff --git a/tool/configure.dart b/tool/configure.dart index 6ee84d63a..d08724e42 100644 --- a/tool/configure.dart +++ b/tool/configure.dart @@ -1057,7 +1057,8 @@ Future generatePubspec( final inputFile = File(pubspecOutputPath); final inputText = await inputFile.readAsString(); final inputLines = inputText.split('\n'); - final dependenciesIndex = inputLines.indexWhere((line) => line.toLowerCase().contains('dependencies:')); + final dependenciesIndex = + inputLines.indexWhere((line) => line.toLowerCase().contains('dependencies:')); var output = cwCore; if (hasMonero) { From fff77519d9cd889b5a17705a1488611640378e33 Mon Sep 17 00:00:00 2001 From: Adegoke David <64401859+Blazebrain@users.noreply.github.com> Date: Thu, 25 Apr 2024 02:14:53 +0100 Subject: [PATCH 07/17] Generic Fixes: Support Errors and others (#1394) * fix: Crypto amout formatting when calculating fiat amount * fix: Issue with some token symbols coming up with a dollar sign * feat: Split transactions to display on history screen token byh token * fix: Remove restriction on balance length * fix: error when a particular token is not available * fix: Remove token transactions when a token is deleted * fix: Revert previous change * make added spl tokens enabled by default fix issue when entering invalid contract address --------- Co-authored-by: OmarHatem --- cw_core/lib/crypto_currency.dart | 2 +- cw_evm/lib/evm_chain_client.dart | 7 ++- cw_evm/lib/evm_chain_wallet.dart | 6 +++ cw_solana/lib/solana_transaction_info.dart | 5 +-- cw_solana/lib/solana_wallet.dart | 52 +++++++++++----------- cw_solana/lib/spl_token.dart | 4 +- lib/entities/calculate_fiat_amount.dart | 2 + lib/ethereum/cw_ethereum.dart | 6 ++- lib/polygon/cw_polygon.dart | 4 +- lib/solana/cw_solana.dart | 6 ++- 10 files changed, 54 insertions(+), 40 deletions(-) diff --git a/cw_core/lib/crypto_currency.dart b/cw_core/lib/crypto_currency.dart index f1c1cd8ae..a7edd409f 100644 --- a/cw_core/lib/crypto_currency.dart +++ b/cw_core/lib/crypto_currency.dart @@ -10,7 +10,7 @@ class CryptoCurrency extends EnumerableItem with Serializable implemen this.fullName, this.iconPath, this.tag, - this.enabled = false, + this.enabled = true, }) : super(title: title, raw: raw); diff --git a/cw_evm/lib/evm_chain_client.dart b/cw_evm/lib/evm_chain_client.dart index eebbe4f4f..8f0df3926 100644 --- a/cw_evm/lib/evm_chain_client.dart +++ b/cw_evm/lib/evm_chain_client.dart @@ -234,14 +234,17 @@ abstract class EVMChainClient { final decodedResponse = jsonDecode(response.body)[0] as Map; + + final symbol = (decodedResponse['symbol'] ?? '') as String; + String filteredSymbol = symbol.replaceFirst(RegExp('^\\\$'), ''); + final name = decodedResponse['name'] ?? ''; - final symbol = decodedResponse['symbol'] ?? ''; final decimal = decodedResponse['decimals'] ?? '0'; final iconPath = decodedResponse['logo'] ?? ''; return Erc20Token( name: name, - symbol: symbol, + symbol: filteredSymbol, contractAddress: contractAddress, decimal: int.tryParse(decimal) ?? 0, iconPath: iconPath, diff --git a/cw_evm/lib/evm_chain_wallet.dart b/cw_evm/lib/evm_chain_wallet.dart index 4193e590a..558013252 100644 --- a/cw_evm/lib/evm_chain_wallet.dart +++ b/cw_evm/lib/evm_chain_wallet.dart @@ -468,9 +468,15 @@ abstract class EVMChainWalletBase await token.delete(); balance.remove(token); + await _removeTokenTransactionsInHistory(token); _updateBalance(); } + Future _removeTokenTransactionsInHistory(Erc20Token token) async { + transactionHistory.transactions.removeWhere((key, value) => value.tokenSymbol == token.title); + await transactionHistory.save(); + } + Future getErc20Token(String contractAddress, String chainName) async => await _client.getErc20Token(contractAddress, chainName); diff --git a/cw_solana/lib/solana_transaction_info.dart b/cw_solana/lib/solana_transaction_info.dart index 1b7610e34..7a0844e52 100644 --- a/cw_solana/lib/solana_transaction_info.dart +++ b/cw_solana/lib/solana_transaction_info.dart @@ -34,10 +34,7 @@ class SolanaTransactionInfo extends TransactionInfo { @override String amountFormatted() { String stringBalance = solAmount.toString(); - - if (stringBalance.toString().length >= 6) { - stringBalance = stringBalance.substring(0, 6); - } + return '$stringBalance $tokenSymbol'; } diff --git a/cw_solana/lib/solana_wallet.dart b/cw_solana/lib/solana_wallet.dart index 43a6d0b83..f3eef465c 100644 --- a/cw_solana/lib/solana_wallet.dart +++ b/cw_solana/lib/solana_wallet.dart @@ -273,32 +273,12 @@ abstract class SolanaWalletBase final transactions = await _client.fetchTransactions(address); - final Map result = {}; - - for (var transactionModel in transactions) { - result[transactionModel.id] = SolanaTransactionInfo( - id: transactionModel.id, - to: transactionModel.to, - from: transactionModel.from, - blockTime: transactionModel.blockTime, - direction: transactionModel.isOutgoingTx - ? TransactionDirection.outgoing - : TransactionDirection.incoming, - solAmount: transactionModel.amount, - isPending: false, - txFee: transactionModel.fee, - tokenSymbol: transactionModel.tokenSymbol, - ); - } - - transactionHistory.addMany(result); - - await transactionHistory.save(); + await _addTransactionsToTransactionHistory(transactions); } /// Fetches the SPL Tokens transactions linked to the token account Public Key Future _updateSPLTokenTransactions() async { - List splTokenTransactions = []; + // List splTokenTransactions = []; // Make a copy of keys to avoid concurrent modification var tokenKeys = List.from(balance.keys); @@ -312,13 +292,20 @@ abstract class SolanaWalletBase _walletKeyPair!, ); - splTokenTransactions.addAll(tokenTxs); + // splTokenTransactions.addAll(tokenTxs); + await _addTransactionsToTransactionHistory(tokenTxs); } } + // await _addTransactionsToTransactionHistory(splTokenTransactions); + } + + Future _addTransactionsToTransactionHistory( + List transactions, + ) async { final Map result = {}; - for (var transactionModel in splTokenTransactions) { + for (var transactionModel in transactions) { result[transactionModel.id] = SolanaTransactionInfo( id: transactionModel.id, to: transactionModel.to, @@ -460,12 +447,23 @@ abstract class SolanaWalletBase await token.delete(); balance.remove(token); + await _removeTokenTransactionsInHistory(token); _updateBalance(); } + Future _removeTokenTransactionsInHistory(SPLToken token) async { + transactionHistory.transactions.removeWhere((key, value) => value.tokenSymbol == token.title); + await transactionHistory.save(); + } + Future getSPLToken(String mintAddress) async { // Convert SPL token mint address to public key - final mintPublicKey = Ed25519HDPublicKey.fromBase58(mintAddress); + final Ed25519HDPublicKey mintPublicKey; + try { + mintPublicKey = Ed25519HDPublicKey.fromBase58(mintAddress); + } catch (_) { + return null; + } // Fetch token's metadata account try { @@ -480,10 +478,12 @@ abstract class SolanaWalletBase iconPath = await _client.getIconImageFromTokenUri(token.uri); } catch (_) {} + String filteredTokenSymbol = token.symbol.replaceFirst(RegExp('^\\\$'), ''); + return SPLToken.fromMetadata( name: token.name, mint: token.mint, - symbol: token.symbol, + symbol: filteredTokenSymbol, mintAddress: mintAddress, iconPath: iconPath, ); diff --git a/cw_solana/lib/spl_token.dart b/cw_solana/lib/spl_token.dart index 0b3b8b372..a40eb0b86 100644 --- a/cw_solana/lib/spl_token.dart +++ b/cw_solana/lib/spl_token.dart @@ -19,7 +19,7 @@ class SPLToken extends CryptoCurrency with HiveObjectMixin { @HiveField(3) final int decimal; - @HiveField(4, defaultValue: false) + @HiveField(4, defaultValue: true) bool _enabled; @HiveField(5) @@ -39,7 +39,7 @@ class SPLToken extends CryptoCurrency with HiveObjectMixin { required this.mint, this.iconPath, this.tag = 'SOL', - bool enabled = false, + bool enabled = true, }) : _enabled = enabled, super( name: mint.toLowerCase(), diff --git a/lib/entities/calculate_fiat_amount.dart b/lib/entities/calculate_fiat_amount.dart index 689ada31b..b0b38eacb 100644 --- a/lib/entities/calculate_fiat_amount.dart +++ b/lib/entities/calculate_fiat_amount.dart @@ -3,6 +3,8 @@ String calculateFiatAmount({double? price, String? cryptoAmount}) { return '0.00'; } + cryptoAmount = cryptoAmount.replaceAll(',', '.'); + final _amount = double.parse(cryptoAmount); final _result = price * _amount; final result = _result < 0 ? _result * -1 : _result; diff --git a/lib/ethereum/cw_ethereum.dart b/lib/ethereum/cw_ethereum.dart index 13fe3aafd..61d5b6ae3 100644 --- a/lib/ethereum/cw_ethereum.dart +++ b/lib/ethereum/cw_ethereum.dart @@ -142,8 +142,10 @@ class CWEthereum extends Ethereum { } wallet as EthereumWallet; - return wallet.erc20Currencies - .firstWhere((element) => transaction.tokenSymbol == element.symbol); + + return wallet.erc20Currencies.firstWhere( + (element) => transaction.tokenSymbol == element.symbol, + ); } @override diff --git a/lib/polygon/cw_polygon.dart b/lib/polygon/cw_polygon.dart index 9f0f9a1bf..5baf4fbbc 100644 --- a/lib/polygon/cw_polygon.dart +++ b/lib/polygon/cw_polygon.dart @@ -140,8 +140,10 @@ class CWPolygon extends Polygon { } wallet as PolygonWallet; + return wallet.erc20Currencies.firstWhere( - (element) => transaction.tokenSymbol.toLowerCase() == element.symbol.toLowerCase()); + (element) => transaction.tokenSymbol.toLowerCase() == element.symbol.toLowerCase(), + ); } @override diff --git a/lib/solana/cw_solana.dart b/lib/solana/cw_solana.dart index 6f4b17309..af66cf3e5 100644 --- a/lib/solana/cw_solana.dart +++ b/lib/solana/cw_solana.dart @@ -110,8 +110,10 @@ class CWSolana extends Solana { } wallet as SolanaWallet; - return wallet.splTokenCurrencies - .firstWhere((element) => transaction.tokenSymbol == element.symbol); + + return wallet.splTokenCurrencies.firstWhere( + (element) => transaction.tokenSymbol == element.symbol, + ); } @override From 3732a4c646c2affe228b055a73e560143f8c5216 Mon Sep 17 00:00:00 2001 From: Konstantin Ullrich Date: Thu, 25 Apr 2024 05:52:24 -0500 Subject: [PATCH 08/17] Language Fixes for DE (#1409) --- lib/buy/dfx/dfx_buy_provider.dart | 4 ++-- lib/entities/provider_types.dart | 2 +- res/values/strings_de.arb | 18 +++++++++--------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/buy/dfx/dfx_buy_provider.dart b/lib/buy/dfx/dfx_buy_provider.dart index 8e2d58d11..b5c5d3b02 100644 --- a/lib/buy/dfx/dfx_buy_provider.dart +++ b/lib/buy/dfx/dfx_buy_provider.dart @@ -23,7 +23,7 @@ class DFXBuyProvider extends BuyProvider { static const walletName = 'CakeWallet'; @override - String get title => 'DFX Connect'; + String get title => 'DFX.swiss'; @override String get providerDescription => S.current.dfx_option_description; @@ -198,7 +198,7 @@ class DFXBuyProvider extends BuyProvider { context: context, builder: (BuildContext context) { return AlertWithOneAction( - alertTitle: "DFX Connect", + alertTitle: "DFX.swiss", alertContent: S.of(context).buy_provider_unavailable + ': $e', buttonText: S.of(context).ok, buttonAction: () => Navigator.of(context).pop()); diff --git a/lib/entities/provider_types.dart b/lib/entities/provider_types.dart index 701781cc2..ca168a299 100644 --- a/lib/entities/provider_types.dart +++ b/lib/entities/provider_types.dart @@ -22,7 +22,7 @@ extension ProviderTypeName on ProviderType { case ProviderType.robinhood: return 'Robinhood Connect'; case ProviderType.dfx: - return 'DFX Connect'; + return 'DFX.swiss'; case ProviderType.onramper: return 'Onramper'; case ProviderType.moonpay: diff --git a/res/values/strings_de.arb b/res/values/strings_de.arb index 7efb0b682..0546140eb 100644 --- a/res/values/strings_de.arb +++ b/res/values/strings_de.arb @@ -50,7 +50,7 @@ "anonpay_description": "Generieren Sie ${type}. Der Empfänger kann ${method} mit jeder unterstützten Kryptowährung verwenden, und Sie erhalten Geld in dieser Wallet.", "apk_update": "APK-Update", "approve": "Genehmigen", - "arrive_in_this_address": "${currency} ${tag}wird an dieser Adresse ankommen", + "arrive_in_this_address": "${currency} ${tag} wird an dieser Adresse ankommen", "ascending": "Aufsteigend", "ask_each_time": "Jedes Mal fragen", "auth_store_ban_timeout": "ban_timeout", @@ -87,7 +87,7 @@ "buy_provider_unavailable": "Anbieter derzeit nicht verfügbar.", "buy_with": "Kaufen mit", "by_cake_pay": "von Cake Pay", - "cake_2fa_preset": "Kuchen 2FA-Voreinstellung", + "cake_2fa_preset": "Cake 2FA-Voreinstellung", "cake_dark_theme": "Cake Dark Thema", "cake_pay_account_note": "Melden Sie sich nur mit einer E-Mail-Adresse an, um Karten anzuzeigen und zu kaufen. Einige sind sogar mit Rabatt erhältlich!", "cake_pay_learn_more": "Kaufen und lösen Sie Geschenkkarten sofort in der App ein!\nWischen Sie von links nach rechts, um mehr zu erfahren.", @@ -120,7 +120,7 @@ "change_wallet_alert_title": "Aktuelle Wallet ändern", "choose_account": "Konto auswählen", "choose_address": "\n\nBitte wählen Sie die Adresse:", - "choose_derivation": "Wählen Sie Brieftaschenableitung", + "choose_derivation": "Wählen Sie Wallet-Ableitung", "choose_from_available_options": "Wähle aus verfügbaren Optionen:", "choose_one": "Wähle ein", "choose_relay": "Bitte wählen Sie ein zu verwendendes Relais aus", @@ -199,7 +199,7 @@ "disable_fiat": "Fiat deaktivieren", "disable_sell": "Verkaufsaktion deaktivieren", "disableBatteryOptimization": "Batterieoptimierung deaktivieren", - "disableBatteryOptimizationDescription": "Möchten Sie die Batterieoptimierung deaktivieren, um die Hintergrundsynchronisierung freier und reibungsloser zu gestalten?", + "disableBatteryOptimizationDescription": "Möchten Sie die Batterieoptimierung deaktivieren, um die Hintergrundsynchronisierung reibungsloser zu gestalten?", "disabled": "Deaktiviert", "discount": "${value} % sparen", "display_settings": "Anzeigeeinstellungen", @@ -459,8 +459,8 @@ "reconnect_alert_text": "Sind Sie sicher, dass Sie sich neu verbinden möchten?", "reconnection": "Neu verbinden", "red_dark_theme": "Red Dark Thema", - "red_light_theme": "Rotlichtthema", - "redeemed": "Versilbert", + "red_light_theme": "Red Light Thema", + "redeemed": "Eingelöst", "refund_address": "Rückerstattungsadresse", "reject": "Ablehnen", "remaining": "Rest", @@ -532,7 +532,7 @@ "seed_alert_title": "Achtung", "seed_alert_yes": "Ja, habe ich", "seed_choose": "Seed-Sprache auswählen", - "seed_hex_form": "Brieftaschensamen (Sechskantform)", + "seed_hex_form": "Seed (Hexformat)", "seed_key": "Seed-Schlüssel", "seed_language": "Seed-Sprache", "seed_language_chinese": "Chinesisch", @@ -584,7 +584,7 @@ "send_your_wallet": "Ihre Wallet", "sending": "Senden", "sent": "Versendet", - "service_health_disabled": "Service Health Bulletin ist behindert", + "service_health_disabled": "Service Health Bulletin ist deaktiviert", "service_health_disabled_message": "Dies ist die Seite \"Service Health Bulletin\", können Sie diese Seite unter Einstellungen -> Privatsphäre aktivieren", "settings": "Einstellungen", "settings_all": "ALLE", @@ -822,4 +822,4 @@ "you_will_get": "Konvertieren zu", "you_will_send": "Konvertieren von", "yy": "YY" -} \ No newline at end of file +} From 190c8e06b9c2121e4694ccdd048b3daf61f99270 Mon Sep 17 00:00:00 2001 From: Konstantin Ullrich Date: Thu, 25 Apr 2024 06:06:11 -0500 Subject: [PATCH 09/17] Use the latest version of the DFX Auth Api to minimize the number of API calls (#1410) --- lib/buy/dfx/dfx_buy_provider.dart | 76 +++++++++---------------------- 1 file changed, 21 insertions(+), 55 deletions(-) diff --git a/lib/buy/dfx/dfx_buy_provider.dart b/lib/buy/dfx/dfx_buy_provider.dart index b5c5d3b02..bf67edd23 100644 --- a/lib/buy/dfx/dfx_buy_provider.dart +++ b/lib/buy/dfx/dfx_buy_provider.dart @@ -17,9 +17,8 @@ class DFXBuyProvider extends BuyProvider { : super(wallet: wallet, isTestEnvironment: isTestEnvironment); static const _baseUrl = 'api.dfx.swiss'; - static const _authPath = '/v1/auth/signMessage'; - static const _signUpPath = '/v1/auth/signUp'; - static const _signInPath = '/v1/auth/signIn'; + // static const _signMessagePath = '/v1/auth/signMessage'; + static const _authPath = '/v1/auth'; static const walletName = 'CakeWallet'; @override @@ -73,21 +72,25 @@ class DFXBuyProvider extends BuyProvider { String get walletAddress => wallet.walletAddresses.primaryAddress ?? wallet.walletAddresses.address; - Future getSignMessage() async { - final uri = Uri.https(_baseUrl, _authPath, {'address': walletAddress}); + Future getSignMessage() async => + "By_signing_this_message,_you_confirm_that_you_are_the_sole_owner_of_the_provided_Blockchain_address._Your_ID:_$walletAddress"; - var response = await http.get(uri, headers: {'accept': 'application/json'}); + // // Lets keep this just in case, but we can avoid this API Call + // Future getSignMessage() async { + // final uri = Uri.https(_baseUrl, _signMessagePath, {'address': walletAddress}); + // + // final response = await http.get(uri, headers: {'accept': 'application/json'}); + // + // if (response.statusCode == 200) { + // final responseBody = jsonDecode(response.body); + // return responseBody['message'] as String; + // } else { + // throw Exception( + // 'Failed to get sign message. Status: ${response.statusCode} ${response.body}'); + // } + // } - if (response.statusCode == 200) { - final responseBody = jsonDecode(response.body); - return responseBody['message'] as String; - } else { - throw Exception( - 'Failed to get sign message. Status: ${response.statusCode} ${response.body}'); - } - } - - Future signUp() async { + Future auth() async { final signMessage = getSignature(await getSignMessage()); final requestBody = jsonEncode({ @@ -96,7 +99,7 @@ class DFXBuyProvider extends BuyProvider { 'signature': signMessage, }); - final uri = Uri.https(_baseUrl, _signUpPath); + final uri = Uri.https(_baseUrl, _authPath); var response = await http.post( uri, headers: {'Content-Type': 'application/json'}, @@ -115,33 +118,6 @@ class DFXBuyProvider extends BuyProvider { } } - Future signIn() async { - final signMessage = getSignature(await getSignMessage()); - - final requestBody = jsonEncode({ - 'address': walletAddress, - 'signature': signMessage, - }); - - final uri = Uri.https(_baseUrl, _signInPath); - var response = await http.post( - uri, - headers: {'Content-Type': 'application/json'}, - body: requestBody, - ); - - if (response.statusCode == 201) { - final responseBody = jsonDecode(response.body); - return responseBody['accessToken'] as String; - } else if (response.statusCode == 403) { - final responseBody = jsonDecode(response.body); - final message = responseBody['message'] ?? 'Service unavailable in your country'; - throw Exception(message); - } else { - throw Exception('Failed to sign in. Status: ${response.statusCode} ${response.body}'); - } - } - String getSignature(String message) { switch (wallet.type) { case WalletType.ethereum: @@ -164,17 +140,7 @@ class DFXBuyProvider extends BuyProvider { final blockchain = this.blockchain; final actionType = isBuyAction == true ? '/buy' : '/sell'; - String accessToken; - - try { - accessToken = await signUp(); - } on Exception catch (e) { - if (e.toString().contains('409')) { - accessToken = await signIn(); - } else { - rethrow; - } - } + final accessToken = await auth(); final uri = Uri.https('services.dfx.swiss', actionType, { 'session': accessToken, From 9ff6da3d5d2db04069deed46c35a15e4138d777e Mon Sep 17 00:00:00 2001 From: Serhii Date: Thu, 25 Apr 2024 19:28:18 +0300 Subject: [PATCH 10/17] dynamic max fee rate value (#1395) --- lib/bitcoin/cw_bitcoin.dart | 6 ++++ lib/src/screens/send/widgets/send_card.dart | 2 ++ .../screens/settings/other_settings_page.dart | 1 + .../widgets/setting_priority_picker_cell.dart | 3 ++ .../rbf_details_list_fee_picker_item.dart | 2 ++ .../transaction_details/rbf_details_page.dart | 1 + lib/src/widgets/picker.dart | 28 +++++++++++++------ lib/src/widgets/standard_picker_list.dart | 3 ++ lib/view_model/send/send_view_model.dart | 7 +++++ .../settings/other_settings_view_model.dart | 7 +++++ .../transaction_details_view_model.dart | 2 ++ tool/configure.dart | 1 + 12 files changed, 54 insertions(+), 9 deletions(-) diff --git a/lib/bitcoin/cw_bitcoin.dart b/lib/bitcoin/cw_bitcoin.dart index 862ce9db5..9bdc0f3ac 100644 --- a/lib/bitcoin/cw_bitcoin.dart +++ b/lib/bitcoin/cw_bitcoin.dart @@ -291,4 +291,10 @@ class CWBitcoin extends Bitcoin { outputsCount, ); } + + @override + int getMaxCustomFeeRate(Object wallet) { + final bitcoinWallet = wallet as ElectrumWallet; + return (bitcoinWallet.feeRate(BitcoinTransactionPriority.fast) * 1.1).round(); + } } diff --git a/lib/src/screens/send/widgets/send_card.dart b/lib/src/screens/send/widgets/send_card.dart index 7c2bfedd0..c9ae5182a 100644 --- a/lib/src/screens/send/widgets/send_card.dart +++ b/lib/src/screens/send/widgets/send_card.dart @@ -675,6 +675,7 @@ class SendCardState extends State with AutomaticKeepAliveClientMixin( @@ -689,6 +690,7 @@ class SendCardState extends State with AutomaticKeepAliveClientMixin extends StandardListRow { this.isGridView = false, this.matchingCriteria, this.customValue, + this.maxValue, this.customItemIndex, this.onItemSelected}) : super( @@ -34,6 +35,7 @@ class SettingsPriorityPickerCell extends StandardListRow { displayItem: (ItemType item) => displayItem!(item, sliderValue.round()), selectedAtIndex: selectedAtIndex, customItemIndex: customItemIndex, + maxValue: maxValue, headerEnabled: false, closeOnItemSelected: false, mainAxisAlignment: MainAxisAlignment.center, @@ -61,6 +63,7 @@ class SettingsPriorityPickerCell extends StandardListRow { final bool isGridView; final bool Function(ItemType, String)? matchingCriteria; double? customValue; + double? maxValue; int? customItemIndex; @override diff --git a/lib/src/screens/transaction_details/rbf_details_list_fee_picker_item.dart b/lib/src/screens/transaction_details/rbf_details_list_fee_picker_item.dart index 8f722ee7e..7615065d7 100644 --- a/lib/src/screens/transaction_details/rbf_details_list_fee_picker_item.dart +++ b/lib/src/screens/transaction_details/rbf_details_list_fee_picker_item.dart @@ -10,6 +10,7 @@ class StandardPickerListItem extends TransactionDetailsListItem { required this.onItemSelected, required this.selectedIdx, required this.customItemIndex, + this.maxValue, required this.customValue}) : super(title: title, value: value); @@ -18,6 +19,7 @@ class StandardPickerListItem extends TransactionDetailsListItem { final Function(double) onSliderChanged; final Function(T) onItemSelected; final int selectedIdx; + final double? maxValue; final int customItemIndex; double customValue; } diff --git a/lib/src/screens/transaction_details/rbf_details_page.dart b/lib/src/screens/transaction_details/rbf_details_page.dart index 875e0a4ef..3faec48a8 100644 --- a/lib/src/screens/transaction_details/rbf_details_page.dart +++ b/lib/src/screens/transaction_details/rbf_details_page.dart @@ -74,6 +74,7 @@ class RBFDetailsPage extends BasePage { selectedIdx: item.selectedIdx, customItemIndex: item.customItemIndex, customValue: item.customValue, + maxValue: item.maxValue, ); } diff --git a/lib/src/widgets/picker.dart b/lib/src/widgets/picker.dart index d87b5721e..b744d1db0 100644 --- a/lib/src/widgets/picker.dart +++ b/lib/src/widgets/picker.dart @@ -27,14 +27,21 @@ class Picker extends StatefulWidget { this.headerEnabled = true, this.closeOnItemSelected = true, this.sliderValue, + this.minValue, + this.maxValue, this.customItemIndex, this.isWrapped = true, this.borderColor, this.onSliderChanged, this.matchingCriteria, - }) : assert(hintText == null || - matchingCriteria != - null); // make sure that if the search field is enabled then there is a searching criteria provided + }) : assert(hintText == null || matchingCriteria != null) { + // make sure that if the search field is enabled then there is a searching criteria provided + if (sliderValue != null && maxValue != null) { + if (sliderValue! > maxValue!) { + sliderValue = maxValue; + } + } + } final int selectedAtIndex; final List items; @@ -49,12 +56,14 @@ class Picker extends StatefulWidget { final String? hintText; final bool headerEnabled; final bool closeOnItemSelected; - final double? sliderValue; + double? sliderValue; + final double? minValue; final int? customItemIndex; final bool isWrapped; final Color? borderColor; final Function(double)? onSliderChanged; final bool Function(Item, String)? matchingCriteria; + final double? maxValue; @override _PickerState createState() => _PickerState(items, images, onItemSelected); @@ -138,7 +147,7 @@ class _PickerState extends State> { containerHeight = height * 0.75; } - final content = Column ( + final content = Column( children: [ if (widget.title?.isNotEmpty ?? false) Container( @@ -211,8 +220,9 @@ class _PickerState extends State> { fontWeight: FontWeight.w500, fontFamily: 'Lato', decoration: TextDecoration.none, - color: - Theme.of(context).extension()!.titleColor, + color: Theme.of(context) + .extension()! + .titleColor, ), ), ) @@ -491,8 +501,8 @@ class _PickerState extends State> { child: Slider( value: widget.sliderValue ?? 1, onChanged: isActivated ? widget.onSliderChanged : null, - min: 1, - max: 100, + min: widget.minValue ?? 1, + max: widget.maxValue ?? 100, divisions: 100, ), ), diff --git a/lib/src/widgets/standard_picker_list.dart b/lib/src/widgets/standard_picker_list.dart index eb1d16900..ea8b07097 100644 --- a/lib/src/widgets/standard_picker_list.dart +++ b/lib/src/widgets/standard_picker_list.dart @@ -15,6 +15,7 @@ class StandardPickerList extends StatefulWidget { required this.selectedIdx, required this.customItemIndex, required this.customValue, + this.maxValue, }) : super(key: key); final String title; @@ -26,6 +27,7 @@ class StandardPickerList extends StatefulWidget { final String value; final int selectedIdx; final double customValue; + final double? maxValue; @override _StandardPickerListState createState() => _StandardPickerListState(); @@ -59,6 +61,7 @@ class _StandardPickerListState extends State> { displayItem: adaptedDisplayItem, selectedAtIndex: selectedIdx, customItemIndex: widget.customItemIndex, + maxValue: widget.maxValue, headerEnabled: false, closeOnItemSelected: false, mainAxisAlignment: MainAxisAlignment.center, diff --git a/lib/view_model/send/send_view_model.dart b/lib/view_model/send/send_view_model.dart index 298cc3eed..2e00d1f0b 100644 --- a/lib/view_model/send/send_view_model.dart +++ b/lib/view_model/send/send_view_model.dart @@ -166,6 +166,13 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor return null; } + int? get maxCustomFeeRate { + if (wallet.type == WalletType.bitcoin) { + return bitcoin!.getMaxCustomFeeRate(wallet); + } + return null; + } + @computed int get customBitcoinFeeRate => _settingsStore.customBitcoinFeeRate; diff --git a/lib/view_model/settings/other_settings_view_model.dart b/lib/view_model/settings/other_settings_view_model.dart index cf410a1a9..0493acf81 100644 --- a/lib/view_model/settings/other_settings_view_model.dart +++ b/lib/view_model/settings/other_settings_view_model.dart @@ -140,6 +140,13 @@ abstract class OtherSettingsViewModelBase with Store { return customItem != null ? priorities.indexOf(customItem) : null; } + int? get maxCustomFeeRate { + if (_wallet.type == WalletType.bitcoin) { + return bitcoin!.getMaxCustomFeeRate(_wallet); + } + return null; + } + @action ProviderType onBuyProviderTypeSelected(ProviderType buyProviderType) => _settingsStore.defaultBuyProviders[walletType] = buyProviderType; diff --git a/lib/view_model/transaction_details_view_model.dart b/lib/view_model/transaction_details_view_model.dart index fd6d3ef6e..be2ebc545 100644 --- a/lib/view_model/transaction_details_view_model.dart +++ b/lib/view_model/transaction_details_view_model.dart @@ -348,12 +348,14 @@ abstract class TransactionDetailsViewModelBase with Store { final customItem = priorities.firstWhereOrNull( (element) => element == sendViewModel.bitcoinTransactionPriorityCustom); final customItemIndex = customItem != null ? priorities.indexOf(customItem) : null; + final maxCustomFeeRate = sendViewModel.maxCustomFeeRate?.toDouble(); RBFListItems.add(StandardPickerListItem( title: S.current.estimated_new_fee, value: bitcoin!.formatterBitcoinAmountToString(amount: newFee) + ' ${walletTypeToCryptoCurrency(wallet.type)}', items: priorityForWalletType(wallet.type), customValue: settingsStore.customBitcoinFeeRate.toDouble(), + maxValue: maxCustomFeeRate, selectedIdx: selectedItem, customItemIndex: customItemIndex ?? 0, displayItem: (dynamic priority, double sliderValue) => diff --git a/tool/configure.dart b/tool/configure.dart index d08724e42..34a39d28b 100644 --- a/tool/configure.dart +++ b/tool/configure.dart @@ -159,6 +159,7 @@ abstract class Bitcoin { Future isChangeSufficientForFee(Object wallet, String txId, String newFee); int getFeeAmountForPriority(Object wallet, TransactionPriority priority, int inputsCount, int outputsCount, {int? size}); int getFeeAmountWithFeeRate(Object wallet, int feeRate, int inputsCount, int outputsCount, {int? size}); + int getMaxCustomFeeRate(Object wallet); } """; From a5a3b4ac0ee0392fd0823f1752536fd04654a49a Mon Sep 17 00:00:00 2001 From: Omar Hatem Date: Fri, 26 Apr 2024 05:32:13 +0300 Subject: [PATCH 11/17] Update crypto_currency.dart --- cw_core/lib/crypto_currency.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cw_core/lib/crypto_currency.dart b/cw_core/lib/crypto_currency.dart index a7edd409f..f1c1cd8ae 100644 --- a/cw_core/lib/crypto_currency.dart +++ b/cw_core/lib/crypto_currency.dart @@ -10,7 +10,7 @@ class CryptoCurrency extends EnumerableItem with Serializable implemen this.fullName, this.iconPath, this.tag, - this.enabled = true, + this.enabled = false, }) : super(title: title, raw: raw); From 7fcf48f91da3d82121704bf25c530549a24c9322 Mon Sep 17 00:00:00 2001 From: Serhii Date: Fri, 26 Apr 2024 19:18:26 +0300 Subject: [PATCH 12/17] Fix estimated fee calculation for customs fee rate (#1406) * Update output.dart * fix estimated fee calculation * Update bitcoin_transaction_priority.dart --- cw_bitcoin/lib/bitcoin_transaction_priority.dart | 2 +- lib/bitcoin/cw_bitcoin.dart | 11 ++++++----- lib/view_model/send/output.dart | 4 ++-- lib/view_model/transaction_details_view_model.dart | 14 +++++--------- tool/configure.dart | 2 +- 5 files changed, 15 insertions(+), 18 deletions(-) diff --git a/cw_bitcoin/lib/bitcoin_transaction_priority.dart b/cw_bitcoin/lib/bitcoin_transaction_priority.dart index d51775368..7c4dcfd5f 100644 --- a/cw_bitcoin/lib/bitcoin_transaction_priority.dart +++ b/cw_bitcoin/lib/bitcoin_transaction_priority.dart @@ -37,7 +37,7 @@ class BitcoinTransactionPriority extends TransactionPriority { switch (this) { case BitcoinTransactionPriority.slow: - label = 'Slow ~24hrs'; // '${S.current.transaction_priority_slow} ~24hrs'; + label = 'Slow ~24hrs+'; // '${S.current.transaction_priority_slow} ~24hrs'; break; case BitcoinTransactionPriority.medium: label = 'Medium'; // S.current.transaction_priority_medium; diff --git a/lib/bitcoin/cw_bitcoin.dart b/lib/bitcoin/cw_bitcoin.dart index 9bdc0f3ac..707f1157b 100644 --- a/lib/bitcoin/cw_bitcoin.dart +++ b/lib/bitcoin/cw_bitcoin.dart @@ -282,13 +282,14 @@ class CWBitcoin extends Bitcoin { } @override - int getFeeAmountWithFeeRate(Object wallet, int feeRate, int inputsCount, int outputsCount, - {int? size}) { + int getEstimatedFeeWithFeeRate(Object wallet, int feeRate, int? amount, + {int? outputsCount, int? size}) { final bitcoinWallet = wallet as ElectrumWallet; - return bitcoinWallet.feeAmountWithFeeRate( + return bitcoinWallet.calculateEstimatedFeeWithFeeRate( feeRate, - inputsCount, - outputsCount, + amount, + outputsCount: outputsCount, + size: size, ); } diff --git a/lib/view_model/send/output.dart b/lib/view_model/send/output.dart index 6bb3fbb31..07d98ff32 100644 --- a/lib/view_model/send/output.dart +++ b/lib/view_model/send/output.dart @@ -126,8 +126,8 @@ abstract class OutputBase with Store { if (_wallet.type == WalletType.bitcoin) { if (_settingsStore.priority[_wallet.type] == bitcoin!.getBitcoinTransactionPriorityCustom()) { - fee = bitcoin!.getFeeAmountWithFeeRate( - _settingsStore.customBitcoinFeeRate, formattedCryptoAmount, 1, 1); + fee = bitcoin!.getEstimatedFeeWithFeeRate(_wallet, + _settingsStore.customBitcoinFeeRate,formattedCryptoAmount); } return bitcoin!.formatterBitcoinAmountToDouble(amount: fee); diff --git a/lib/view_model/transaction_details_view_model.dart b/lib/view_model/transaction_details_view_model.dart index be2ebc545..faa49dfc4 100644 --- a/lib/view_model/transaction_details_view_model.dart +++ b/lib/view_model/transaction_details_view_model.dart @@ -390,16 +390,12 @@ abstract class TransactionDetailsViewModelBase with Store { String setNewFee({double? value, required TransactionPriority priority}) { newFee = priority == bitcoin!.getBitcoinTransactionPriorityCustom() && value != null - ? bitcoin!.getFeeAmountWithFeeRate( - wallet, - value.round(), - transactionInfo.inputAddresses?.length ?? 1, - transactionInfo.outputAddresses?.length ?? 1) + ? bitcoin!.getEstimatedFeeWithFeeRate(wallet, value.round(), transactionInfo.amount) : bitcoin!.getFeeAmountForPriority( - wallet, - priority, - transactionInfo.inputAddresses?.length ?? 1, - transactionInfo.outputAddresses?.length ?? 1); + wallet, + priority, + transactionInfo.inputAddresses?.length ?? 1, + transactionInfo.outputAddresses?.length ?? 1); return bitcoin!.formatterBitcoinAmountToString(amount: newFee); } diff --git a/tool/configure.dart b/tool/configure.dart index 34a39d28b..3b73bfe80 100644 --- a/tool/configure.dart +++ b/tool/configure.dart @@ -158,7 +158,7 @@ abstract class Bitcoin { Future canReplaceByFee(Object wallet, String transactionHash); Future isChangeSufficientForFee(Object wallet, String txId, String newFee); int getFeeAmountForPriority(Object wallet, TransactionPriority priority, int inputsCount, int outputsCount, {int? size}); - int getFeeAmountWithFeeRate(Object wallet, int feeRate, int inputsCount, int outputsCount, {int? size}); + int getEstimatedFeeWithFeeRate(Object wallet, int feeRate, int? amount, {int? outputsCount, int? size}); int getMaxCustomFeeRate(Object wallet); } """; From a6dc9bf9d675d27297afbdec616ba5e1d251d566 Mon Sep 17 00:00:00 2001 From: Serhii Date: Fri, 26 Apr 2024 19:18:35 +0300 Subject: [PATCH 13/17] Update electrum_wallet.dart (#1411) --- cw_bitcoin/lib/electrum_wallet.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cw_bitcoin/lib/electrum_wallet.dart b/cw_bitcoin/lib/electrum_wallet.dart index 5bed6a449..6b305722e 100644 --- a/cw_bitcoin/lib/electrum_wallet.dart +++ b/cw_bitcoin/lib/electrum_wallet.dart @@ -1037,9 +1037,11 @@ abstract class ElectrumWalletBase return Future.wait(addressesByType.map((addressRecord) async { final history = await _fetchAddressHistory(addressRecord, addressesSet, currentHeight); + final balance = await electrumClient.getBalance(addressRecord.scriptHash!); if (history.isNotEmpty) { addressRecord.txCount = history.length; + addressRecord.balance = balance['confirmed'] as int? ?? 0; historiesWithDetails.addAll(history); final matchedAddresses = From f3160860b1796ef0abe41299eb954ce26c1b899b Mon Sep 17 00:00:00 2001 From: Omar Hatem Date: Fri, 26 Apr 2024 22:13:44 +0300 Subject: [PATCH 14/17] Better handle corrupted wallets (#1384) * Fix exchanges not showing * Fix button text on Monero receive screen * Temp fix for ERC20 and SPL tokens not having raw value * fallback to other wallets if the current wallet is corrupted so we give user access to the app --------- Co-authored-by: tuxsudo --- lib/core/wallet_loading_service.dart | 61 ++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 17 deletions(-) diff --git a/lib/core/wallet_loading_service.dart b/lib/core/wallet_loading_service.dart index 3323e7831..1f17a7a1c 100644 --- a/lib/core/wallet_loading_service.dart +++ b/lib/core/wallet_loading_service.dart @@ -1,27 +1,28 @@ import 'package:cake_wallet/core/generate_wallet_password.dart'; import 'package:cake_wallet/core/key_service.dart'; import 'package:cake_wallet/entities/preferences_key.dart'; +import 'package:cake_wallet/utils/exception_handler.dart'; +import 'package:cw_core/cake_hive.dart'; import 'package:cw_core/wallet_base.dart'; +import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_service.dart'; import 'package:cw_core/wallet_type.dart'; +import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; class WalletLoadingService { - WalletLoadingService( - this.sharedPreferences, this.keyService, this.walletServiceFactory); + WalletLoadingService(this.sharedPreferences, this.keyService, this.walletServiceFactory); final SharedPreferences sharedPreferences; final KeyService keyService; final WalletService Function(WalletType type) walletServiceFactory; - Future renameWallet( - WalletType type, String name, String newName) async { + Future renameWallet(WalletType type, String name, String newName) async { final walletService = walletServiceFactory.call(type); final password = await keyService.getWalletPassword(walletName: name); // Save the current wallet's password to the new wallet name's key - await keyService.saveWalletPassword( - walletName: newName, password: password); + await keyService.saveWalletPassword(walletName: newName, password: password); // Delete previous wallet name from keyService to keep only new wallet's name // otherwise keeps duplicate (old and new names) await keyService.deleteWalletPassword(walletName: name); @@ -38,15 +39,43 @@ class WalletLoadingService { } Future load(WalletType type, String name) async { - final walletService = walletServiceFactory.call(type); - final password = await keyService.getWalletPassword(walletName: name); - final wallet = await walletService.openWallet(name, password); + try { + final walletService = walletServiceFactory.call(type); + final password = await keyService.getWalletPassword(walletName: name); + final wallet = await walletService.openWallet(name, password); - if (type == WalletType.monero) { - await updateMoneroWalletPassword(wallet); + if (type == WalletType.monero) { + await updateMoneroWalletPassword(wallet); + } + + return wallet; + } catch (error, stack) { + ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stack)); + + // try opening another wallet that is not corrupted to give user access to the app + final walletInfoSource = await CakeHive.openBox(WalletInfo.boxName); + + for (var walletInfo in walletInfoSource.values) { + try { + final walletService = walletServiceFactory.call(walletInfo.type); + final password = await keyService.getWalletPassword(walletName: walletInfo.name); + final wallet = await walletService.openWallet(walletInfo.name, password); + + if (walletInfo.type == WalletType.monero) { + await updateMoneroWalletPassword(wallet); + } + + await sharedPreferences.setString(PreferencesKey.currentWalletName, wallet.name); + await sharedPreferences.setInt( + PreferencesKey.currentWalletType, serializeToInt(wallet.type)); + + return wallet; + } catch (_) {} + } + + // if all user's wallets are corrupted throw exception + throw error; } - - return wallet; } Future updateMoneroWalletPassword(WalletBase wallet) async { @@ -61,11 +90,9 @@ class WalletLoadingService { // Save new generated password with backup key for case where // wallet will change password, but it will fail to update in secure storage final bakWalletName = '#__${wallet.name}_bak__#'; - await keyService.saveWalletPassword( - walletName: bakWalletName, password: password); + await keyService.saveWalletPassword(walletName: bakWalletName, password: password); await wallet.changePassword(password); - await keyService.saveWalletPassword( - walletName: wallet.name, password: password); + await keyService.saveWalletPassword(walletName: wallet.name, password: password); isPasswordUpdated = true; await sharedPreferences.setBool(key, isPasswordUpdated); } From 9e4a7f4331d0ed9a26f5d1c73135a7ae06b4d8c8 Mon Sep 17 00:00:00 2001 From: Omar Hatem Date: Fri, 26 Apr 2024 22:29:31 +0300 Subject: [PATCH 15/17] Enhance bitcoin error message (#1399) * Enhance bitcoin error message * fix: unconfirmed spends, spend confirmed first, wrong balance exception * Minor fixes --------- Co-authored-by: Rafael Saes --- cw_bitcoin/lib/electrum_wallet.dart | 44 +++++++++++++++++-- cw_bitcoin/lib/exceptions.dart | 4 +- .../lib/pending_bitcoin_transaction.dart | 2 + cw_bitcoin/pubspec.lock | 34 +++++++------- .../src/pending_bitcoin_cash_transaction.dart | 2 + cw_core/lib/exceptions.dart | 6 ++- cw_core/lib/unspent_transaction_output.dart | 1 + lib/src/screens/send/send_page.dart | 2 +- lib/view_model/send/send_view_model.dart | 2 +- 9 files changed, 72 insertions(+), 25 deletions(-) diff --git a/cw_bitcoin/lib/electrum_wallet.dart b/cw_bitcoin/lib/electrum_wallet.dart index 6b305722e..4a76ee5dd 100644 --- a/cw_bitcoin/lib/electrum_wallet.dart +++ b/cw_bitcoin/lib/electrum_wallet.dart @@ -203,10 +203,14 @@ abstract class ElectrumWalletBase List privateKeys = []; int allInputsAmount = 0; + bool spendsUnconfirmedTX = false; + for (int i = 0; i < unspentCoins.length; i++) { final utx = unspentCoins[i]; - if (utx.isSending) { + if (utx.isSending && !utx.isFrozen) { + if (!spendsUnconfirmedTX) spendsUnconfirmedTX = utx.confirmations == 0; + allInputsAmount += utx.value; final address = addressTypeFromStr(utx.address, network); @@ -264,6 +268,10 @@ abstract class ElectrumWalletBase // Here, when sending all, the output amount equals to the input value - fee to fully spend every input on the transaction and have no amount left for change int amount = allInputsAmount - fee; + if (amount <= 0) { + throw BitcoinTransactionWrongBalanceException(); + } + // Attempting to send less than the dust limit if (_isBelowDust(amount)) { throw BitcoinTransactionNoDustException(); @@ -288,6 +296,7 @@ abstract class ElectrumWalletBase isSendAll: true, hasChange: false, memo: memo, + spendsUnconfirmedTX: spendsUnconfirmedTX, ); } @@ -297,17 +306,25 @@ abstract class ElectrumWalletBase int feeRate, { int? inputsCount, String? memo, + bool? useUnconfirmed, }) async { final utxos = []; List privateKeys = []; int allInputsAmount = 0; + bool spendsUnconfirmedTX = false; int leftAmount = credentialsAmount; - final sendingCoins = unspentCoins.where((utx) => utx.isSending).toList(); + final sendingCoins = unspentCoins.where((utx) => utx.isSending && !utx.isFrozen).toList(); + final unconfirmedCoins = sendingCoins.where((utx) => utx.confirmations == 0).toList(); for (int i = 0; i < sendingCoins.length; i++) { final utx = sendingCoins[i]; + final isUncormirmed = utx.confirmations == 0; + if (useUnconfirmed != true && isUncormirmed) continue; + + if (!spendsUnconfirmedTX) spendsUnconfirmedTX = isUncormirmed; + allInputsAmount += utx.value; leftAmount = leftAmount - utx.value; @@ -345,11 +362,23 @@ abstract class ElectrumWalletBase } final spendingAllCoins = sendingCoins.length == utxos.length; + final spendingAllConfirmedCoins = + !spendsUnconfirmedTX && utxos.length == sendingCoins.length - unconfirmedCoins.length; // How much is being spent - how much is being sent int amountLeftForChangeAndFee = allInputsAmount - credentialsAmount; if (amountLeftForChangeAndFee <= 0) { + if (!spendingAllCoins) { + return estimateTxForAmount( + credentialsAmount, + outputs, + feeRate, + inputsCount: utxos.length + 1, + memo: memo, + useUnconfirmed: useUnconfirmed ?? spendingAllConfirmedCoins, + ); + } throw BitcoinTransactionWrongBalanceException(); } @@ -403,6 +432,7 @@ abstract class ElectrumWalletBase feeRate, inputsCount: utxos.length + 1, memo: memo, + useUnconfirmed: useUnconfirmed ?? spendingAllConfirmedCoins, ); } @@ -449,6 +479,7 @@ abstract class ElectrumWalletBase feeRate, inputsCount: utxos.length + 1, memo: memo, + useUnconfirmed: useUnconfirmed ?? spendingAllConfirmedCoins, ); } } @@ -461,6 +492,7 @@ abstract class ElectrumWalletBase hasChange: true, isSendAll: false, memo: memo, + spendsUnconfirmedTX: spendsUnconfirmedTX, ); } @@ -531,7 +563,7 @@ abstract class ElectrumWalletBase network: network, memo: estimatedTx.memo, outputOrdering: BitcoinOrdering.none, - enableRBF: true, + enableRBF: !estimatedTx.spendsUnconfirmedTX, ); } else { txb = BitcoinTransactionBuilder( @@ -541,7 +573,7 @@ abstract class ElectrumWalletBase network: network, memo: estimatedTx.memo, outputOrdering: BitcoinOrdering.none, - enableRBF: true, + enableRBF: !estimatedTx.spendsUnconfirmedTX, ); } @@ -721,6 +753,7 @@ abstract class ElectrumWalletBase final tx = await fetchTransactionInfo( hash: coin.hash, height: 0, myAddresses: addressesSet); coin.isChange = tx?.direction == TransactionDirection.outgoing; + coin.confirmations = tx?.confirmations; updatedUnspentCoins.add(coin); } catch (_) {} })))); @@ -745,6 +778,7 @@ abstract class ElectrumWalletBase coin.isFrozen = coinInfo.isFrozen; coin.isSending = coinInfo.isSending; coin.note = coinInfo.note; + coin.bitcoinAddressRecord.balance += coinInfo.value; } else { _addCoinInfo(coin); } @@ -1272,6 +1306,7 @@ class EstimatedTxResult { required this.hasChange, required this.isSendAll, this.memo, + required this.spendsUnconfirmedTX, }); final List utxos; @@ -1281,6 +1316,7 @@ class EstimatedTxResult { final bool hasChange; final bool isSendAll; final String? memo; + final bool spendsUnconfirmedTX; } BitcoinBaseAddress addressTypeFromStr(String address, BasedUtxoNetwork network) { diff --git a/cw_bitcoin/lib/exceptions.dart b/cw_bitcoin/lib/exceptions.dart index 4b03eb922..979c1a433 100644 --- a/cw_bitcoin/lib/exceptions.dart +++ b/cw_bitcoin/lib/exceptions.dart @@ -15,7 +15,9 @@ class BitcoinTransactionNoDustOnChangeException extends TransactionNoDustOnChang BitcoinTransactionNoDustOnChangeException(super.max, super.min); } -class BitcoinTransactionCommitFailed extends TransactionCommitFailed {} +class BitcoinTransactionCommitFailed extends TransactionCommitFailed { + BitcoinTransactionCommitFailed({super.errorMessage}); +} class BitcoinTransactionCommitFailedDustChange extends TransactionCommitFailedDustChange {} diff --git a/cw_bitcoin/lib/pending_bitcoin_transaction.dart b/cw_bitcoin/lib/pending_bitcoin_transaction.dart index 529ac61da..a59b4f429 100644 --- a/cw_bitcoin/lib/pending_bitcoin_transaction.dart +++ b/cw_bitcoin/lib/pending_bitcoin_transaction.dart @@ -73,7 +73,9 @@ class PendingBitcoinTransaction with PendingTransaction { if (error.contains("bad-txns-vout-negative")) { throw BitcoinTransactionCommitFailedVoutNegative(); } + throw BitcoinTransactionCommitFailed(errorMessage: error); } + throw BitcoinTransactionCommitFailed(); } diff --git a/cw_bitcoin/pubspec.lock b/cw_bitcoin/pubspec.lock index 53cf550c8..50cd432c0 100644 --- a/cw_bitcoin/pubspec.lock +++ b/cw_bitcoin/pubspec.lock @@ -21,10 +21,10 @@ packages: dependency: transitive description: name: args - sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.5.0" asn1lib: dependency: transitive description: @@ -80,7 +80,7 @@ packages: description: path: "." ref: cake-update-v2 - resolved-ref: "3fd81d238b990bb767fc7a4fdd5053a22a142e2e" + resolved-ref: "01d844a5f5a520a31df5254e34169af4664aa769" url: "https://github.com/cake-tech/bitcoin_base.git" source: git version: "4.2.0" @@ -153,10 +153,10 @@ packages: dependency: "direct dev" description: name: build_runner - sha256: "581bacf68f89ec8792f5e5a0b2c4decd1c948e97ce659dc783688c8a88fbec21" + sha256: "3ac61a79bfb6f6cc11f693591063a7f19a7af628dc52f141743edac5c16e8c22" url: "https://pub.dev" source: hosted - version: "2.4.8" + version: "2.4.9" build_runner_core: dependency: transitive description: @@ -177,10 +177,10 @@ packages: dependency: transitive description: name: built_value - sha256: a3ec2e0f967bc47f69f95009bb93db936288d61d5343b9436e378b28a2f830c6 + sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb url: "https://pub.dev" source: hosted - version: "8.9.0" + version: "8.9.2" characters: dependency: transitive description: @@ -309,10 +309,10 @@ packages: dependency: "direct main" description: name: flutter_mobx - sha256: "4a5d062ff85ed3759f4aac6410ff0ffae32e324b2e71ca722ae1b37b32e865f4" + sha256: "859fbf452fa9c2519d2700b125dd7fb14c508bbdd7fb65e26ca8ff6c92280e2e" url: "https://pub.dev" source: hosted - version: "2.2.0+2" + version: "2.2.1+1" flutter_test: dependency: "direct dev" description: flutter @@ -322,10 +322,10 @@ packages: dependency: transitive description: name: frontend_server_client - sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "4.0.0" glob: dependency: transitive description: @@ -466,10 +466,10 @@ packages: dependency: "direct main" description: name: mobx - sha256: "74ee54012dc7c1b3276eaa960a600a7418ef5f9997565deb8fca1fd88fb36b78" + sha256: "63920b27b32ad1910adfe767ab1750e4c212e8923232a1f891597b362074ea5e" url: "https://pub.dev" source: hosted - version: "2.3.0+1" + version: "2.3.3+2" mobx_codegen: dependency: "direct dev" description: @@ -570,10 +570,10 @@ packages: dependency: transitive description: name: pointycastle - sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29" + sha256: "70fe966348fe08c34bf929582f1d8247d9d9408130723206472b4687227e4333" url: "https://pub.dev" source: hosted - version: "3.7.4" + version: "3.8.0" pool: dependency: transitive description: @@ -586,10 +586,10 @@ packages: dependency: transitive description: name: provider - sha256: "9a96a0a19b594dbc5bf0f1f27d2bc67d5f95957359b461cd9feb44ed6ae75096" + sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c url: "https://pub.dev" source: hosted - version: "6.1.1" + version: "6.1.2" pub_semver: dependency: transitive description: diff --git a/cw_bitcoin_cash/lib/src/pending_bitcoin_cash_transaction.dart b/cw_bitcoin_cash/lib/src/pending_bitcoin_cash_transaction.dart index da4710a8b..6d2ab4696 100644 --- a/cw_bitcoin_cash/lib/src/pending_bitcoin_cash_transaction.dart +++ b/cw_bitcoin_cash/lib/src/pending_bitcoin_cash_transaction.dart @@ -62,7 +62,9 @@ class PendingBitcoinCashTransaction with PendingTransaction { if (error.contains("bad-txns-vout-negative")) { throw BitcoinTransactionCommitFailedVoutNegative(); } + throw BitcoinTransactionCommitFailed(errorMessage: error); } + throw BitcoinTransactionCommitFailed(); } diff --git a/cw_core/lib/exceptions.dart b/cw_core/lib/exceptions.dart index 848ac40e6..d07da8109 100644 --- a/cw_core/lib/exceptions.dart +++ b/cw_core/lib/exceptions.dart @@ -19,7 +19,11 @@ class TransactionNoDustOnChangeException implements Exception { final String min; } -class TransactionCommitFailed implements Exception {} +class TransactionCommitFailed implements Exception { + final String? errorMessage; + + TransactionCommitFailed({this.errorMessage}); +} class TransactionCommitFailedDustChange implements Exception {} diff --git a/cw_core/lib/unspent_transaction_output.dart b/cw_core/lib/unspent_transaction_output.dart index b52daf43c..595df18f4 100644 --- a/cw_core/lib/unspent_transaction_output.dart +++ b/cw_core/lib/unspent_transaction_output.dart @@ -14,6 +14,7 @@ class Unspent { bool isChange; bool isSending; bool isFrozen; + int? confirmations; String note; bool get isP2wpkh => address.startsWith('bc') || address.startsWith('ltc'); diff --git a/lib/src/screens/send/send_page.dart b/lib/src/screens/send/send_page.dart index 970bb31f2..93fadea72 100644 --- a/lib/src/screens/send/send_page.dart +++ b/lib/src/screens/send/send_page.dart @@ -100,7 +100,7 @@ class SendPage extends BasePage { AppBarStyle get appBarStyle => AppBarStyle.transparent; double _sendCardHeight(BuildContext context) { - double initialHeight = 450; + double initialHeight = 480; if (sendViewModel.hasCoinControl) { initialHeight += 35; } diff --git a/lib/view_model/send/send_view_model.dart b/lib/view_model/send/send_view_model.dart index 2e00d1f0b..cabb723e1 100644 --- a/lib/view_model/send/send_view_model.dart +++ b/lib/view_model/send/send_view_model.dart @@ -562,7 +562,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor return S.current.tx_no_dust_exception; } if (error is TransactionCommitFailed) { - return S.current.tx_commit_failed; + return "${S.current.tx_commit_failed}${error.errorMessage != null ? "\n\n${error.errorMessage}" : ""}"; } if (error is TransactionCommitFailedDustChange) { return S.current.tx_rejected_dust_change; From 509b92e97f51731a73736ca5c27e3e2d7df3def4 Mon Sep 17 00:00:00 2001 From: Matthew Fosse Date: Mon, 29 Apr 2024 17:49:56 -0700 Subject: [PATCH 16/17] Bitcoin derivations (#1089) * - Update and Fix Conflicts with main * Add Balances for ERC20 tokens * Fix conflicts with main * Add erc20 abi json * Add send erc20 tokens initial function * add missing getHeightByDate in Haven [skip ci] * Allow contacts and wallets from the same tag * Add Shiba Inu icon * Add send ERC-20 tokens initial flow * Add missing import in generated file * Add initial approach for transaction sending for ERC-20 tokens * Refactor signing/sending transactions * Add initial flow for transactions subscription * Refactor signing/sending transactions * Add home settings icon * Fix conflicts with main * Initial flow for home settings * Add logic flow for adding erc20 tokens * Fix initial UI * Finalize UI for Tokens * Integrate UI with Ethereum flow * Add "Enable/Disable" feature for ERC20 tokens * Add initial Erc20 tokens * Add Sorting and Pin Native Token features * Fix price sorting * Sort tokens list as well when Sort criteria changes * - Improve sorting balances flow - Add initial add token from search bar flow * Fix Accounts Popup UI * Fix Pin native token * Fix Enabling/Disabling tokens Fix sorting by fiat once app is opened Improve token availability mechanism * Fix deleting token Fix renaming tokens * Fix issue with search * Add more tokens * - Fix scroll issue - Add ERC20 tokens placeholder image in picker * - Separate and organize default erc20 tokens - Fix scrolling - Add token placeholder images in picker - Sort disabled tokens alphabetically * Change BNB token initial availability [skip ci] * Fix Conflicts with main * Fix Conflicts with main * Add Verse ERC20 token to the initial tokens list * Add rename wallet to Ethereum * Integrate EtherScan API for fetching address transactions Generate Ethereum specific secrets in Ethereum package * Adjust transactions fiat price for ERC20 tokens * Free Up GitHub Actions Ubuntu Runner Disk Space * Free Up GitHub Actions Ubuntu Runner Disk space (trial 2) * Fix Transaction Fee display * Save transaction history * Enhance loading time for erc20 tokens transactions * Minor Fixes and Enhancements * Fix sending erc20 fix block explorer issue * Fix int overflow * Fix transaction amount conversions * Minor: `slow` -> `Slow` [skip-ci] * initial changes * more base config stuff * config changes * successfully builds! * save * successfully add nano wallet * save * seed generation * receive screen + node screen working * tx history working and fiat fixes * balance working * derivation updates * nano-unfinished * sends working * remove fees from send screen, send and receive transactions working * fixes + auto receive incoming txs * fix for scanning QR codes * save * update translations * fixes * more fixes * more strings * small fix * fix github actions workflow * potential fix * potential fix * ci/cd fix * change rep working * seed generation fixes * fixes * save * change rep screen functional * save * banano changes * fixes, start adding ui for PoW * pow node changes * update translations * fix * account changing barely working * save * disable account generation * small fix * save * UI work * save * fixes after merge main * fixes * remove monero stuff, work on derivation ui * lots of fixes + finish up seed derivation * last minute fixes * node related fixes * more fixes * small fix * more fixes * fixes * pretty big refactor for pow, still some bugs * finally works! * get transactions after send * fix * merge conflict fixes * save * fix pow node showing up twice * done * initial changes * small fix * more merge fixes * fixes * more fixes * fix * save * fix manage pow nodes setting appearing on other wallets * fix contact bug * fixes * fiat fixes * save * save * save * save * updates * cleanup * restore fix * fixes * remove deprecated alert * fix * small fix * remove outdated warning * electrum restore fixes * fixes * fixes * fix * derivation fixes * nano fixes pt.1 * nano fixes pt.2 * bip39 fixes * pownode refactor * nodes pages fixes * observer fix * ssl fix * remove old references * remove unused imports * code cleanup * small fix * small potential fix * save * derivation fixes * deterministic fix * fix pt.2 * derivation class fixes * review fixes from nano that also apply here * formatting * stuff that should've stayed deleted * post merge fixes * remove problematic imports and duplicate changes * Delete lib/nano/nano.dart * move wallet restore page proxy code to the view model * fix dashboard page indicators being the same color * debatably better refactoring of derivationInfo, migration needed * additional refactor improvements * blanket comment some stuff out to narrow down this issue * refactor fixes * fix nano exchange * fix , bug, i.e. replace , with . when making a nano transaction * fix nano sending, update restore page wording, and other minor fixes * write migration for existing bitcoin and nano wallets * merge fixes * minor fixes * use default derivation type when restoring from qr code * fixes for restoring * fixes * fixes * merge fix * Fix issues with Creating Electrum and Restoring Bip39 * updates & fixes * Add missing case for no transactions BIP39 wallet restore * Make the default BIP39 the 84 derivation path * Add Samourai Deposit * litecoin mnemonic error fix * Bip39 passphrase support (#1412) * save * passphrase working * fix for when loading wallets + translation update * minor fix * Fix Nano * minor fix [skip ci] --------- Co-authored-by: OmarHatem * change error state seed conditions into throwables [skip ci] * litecoin fixes * Bip39 minor enhancements (#1416) * minor enhancements * rename bitcoin_derivations -> electrum_derivations * Remove duplicate derivations handle default case * minor fix * Enable passphrase for Litecoin * obscure text of passphrase --------- Co-authored-by: OmarHatem Co-authored-by: Justin Ehrenhofer Co-authored-by: fossephate --- assets/nano_pow_node_list.yml | 2 +- cw_bitcoin/lib/bitcoin_mnemonic.dart | 32 +-- cw_bitcoin/lib/bitcoin_wallet.dart | 56 +++++- .../bitcoin_wallet_creation_credentials.dart | 33 +++- cw_bitcoin/lib/bitcoin_wallet_service.dart | 7 +- cw_bitcoin/lib/electrum_derivations.dart | 104 ++++++++++ cw_bitcoin/lib/electrum_wallet.dart | 8 +- cw_bitcoin/lib/electrum_wallet_snapshot.dart | 15 ++ cw_bitcoin/lib/litecoin_wallet.dart | 18 +- cw_bitcoin/lib/litecoin_wallet_service.dart | 7 +- cw_bitcoin/lib/utils.dart | 67 +++++-- cw_bitcoin/pubspec.lock | 32 ++- cw_core/lib/hive_type_ids.dart | 3 +- cw_core/lib/wallet_credentials.dart | 14 +- cw_core/lib/wallet_info.dart | 79 +++++--- cw_core/pubspec.lock | 32 ++- cw_nano/lib/nano_wallet.dart | 7 +- .../lib/nano_wallet_creation_credentials.dart | 19 +- cw_nano/lib/nano_wallet_service.dart | 12 +- lib/bitcoin/cw_bitcoin.dart | 186 +++++++++++++++--- lib/entities/default_settings_migration.dart | 18 ++ lib/entities/parse_address_from_domain.dart | 6 +- lib/main.dart | 6 +- lib/nano/cw_nano.dart | 74 +++++-- .../wallet_restore_choose_derivation.dart | 22 +-- .../wallet_restore_from_seed_form.dart | 30 ++- .../screens/restore/wallet_restore_page.dart | 140 +++++-------- .../screens/wallet_list/wallet_list_page.dart | 4 +- lib/src/widgets/base_text_form_field.dart | 3 + .../restore/restore_from_qr_vm.dart | 44 +++-- lib/view_model/send/send_view_model.dart | 2 +- lib/view_model/wallet_creation_vm.dart | 46 ++++- lib/view_model/wallet_restore_view_model.dart | 52 +++-- res/values/strings_ar.arb | 1 + res/values/strings_bg.arb | 1 + res/values/strings_cs.arb | 1 + res/values/strings_de.arb | 5 +- res/values/strings_en.arb | 1 + res/values/strings_es.arb | 1 + res/values/strings_fr.arb | 1 + res/values/strings_ha.arb | 1 + res/values/strings_hi.arb | 1 + res/values/strings_hr.arb | 1 + res/values/strings_id.arb | 1 + res/values/strings_it.arb | 1 + res/values/strings_ja.arb | 1 + res/values/strings_ko.arb | 3 +- res/values/strings_my.arb | 1 + res/values/strings_nl.arb | 1 + res/values/strings_pl.arb | 1 + res/values/strings_pt.arb | 1 + res/values/strings_ru.arb | 1 + res/values/strings_th.arb | 1 + res/values/strings_tl.arb | 1 + res/values/strings_tr.arb | 1 + res/values/strings_uk.arb | 1 + res/values/strings_ur.arb | 1 + res/values/strings_yo.arb | 1 + res/values/strings_zh.arb | 1 + tool/configure.dart | 37 +++- 60 files changed, 908 insertions(+), 341 deletions(-) create mode 100644 cw_bitcoin/lib/electrum_derivations.dart diff --git a/assets/nano_pow_node_list.yml b/assets/nano_pow_node_list.yml index b90845034..3bbc7c3fb 100644 --- a/assets/nano_pow_node_list.yml +++ b/assets/nano_pow_node_list.yml @@ -6,4 +6,4 @@ uri: workers.perish.co - uri: worker.nanoriver.cc - useSSL: true \ No newline at end of file + useSSL: true diff --git a/cw_bitcoin/lib/bitcoin_mnemonic.dart b/cw_bitcoin/lib/bitcoin_mnemonic.dart index 9163fcb11..4a01d6ddc 100644 --- a/cw_bitcoin/lib/bitcoin_mnemonic.dart +++ b/cw_bitcoin/lib/bitcoin_mnemonic.dart @@ -90,8 +90,7 @@ List prefixMatches(String source, List prefixes) { return prefixes.map((prefix) => hx.startsWith(prefix.toLowerCase())).toList(); } -Future generateMnemonic( - {int strength = 264, String prefix = segwit}) async { +Future generateElectrumMnemonic({int strength = 264, String prefix = segwit}) async { final wordBitlen = logBase(wordlist.length, 2).ceil(); final wordCount = strength / wordBitlen; final byteCount = ((wordCount * wordBitlen).ceil() / 8).ceil(); @@ -106,22 +105,29 @@ Future generateMnemonic( return result; } +Future checkIfMnemonicIsElectrum2(String mnemonic) async { + return prefixMatches(mnemonic, [segwit]).first; +} + +Future getMnemonicHash(String mnemonic) async { + final hmacSha512 = Hmac(sha512, utf8.encode('Seed version')); + final digest = hmacSha512.convert(utf8.encode(normalizeText(mnemonic))); + final hx = digest.toString(); + return hx; +} + Future mnemonicToSeedBytes(String mnemonic, {String prefix = segwit}) async { - final pbkdf2 = cryptography.Pbkdf2( - macAlgorithm: cryptography.Hmac.sha512(), - iterations: 2048, - bits: 512); + final pbkdf2 = + cryptography.Pbkdf2(macAlgorithm: cryptography.Hmac.sha512(), iterations: 2048, bits: 512); final text = normalizeText(mnemonic); // pbkdf2.deriveKey(secretKey: secretKey, nonce: nonce) final key = await pbkdf2.deriveKey( - secretKey: cryptography.SecretKey(text.codeUnits), - nonce: 'electrum'.codeUnits); + secretKey: cryptography.SecretKey(text.codeUnits), nonce: 'electrum'.codeUnits); final bytes = await key.extractBytes(); return Uint8List.fromList(bytes); } -bool matchesAnyPrefix(String mnemonic) => - prefixMatches(mnemonic, [segwit]).any((el) => el); +bool matchesAnyPrefix(String mnemonic) => prefixMatches(mnemonic, [segwit]).any((el) => el); bool validateMnemonic(String mnemonic, {String prefix = segwit}) { try { @@ -208,10 +214,8 @@ String removeCJKSpaces(String source) { } String normalizeText(String source) { - final res = removeCombiningCharacters(unorm.nfkd(source).toLowerCase()) - .trim() - .split('/\s+/') - .join(' '); + final res = + removeCombiningCharacters(unorm.nfkd(source).toLowerCase()).trim().split('/\s+/').join(' '); return removeCJKSpaces(res); } diff --git a/cw_bitcoin/lib/bitcoin_wallet.dart b/cw_bitcoin/lib/bitcoin_wallet.dart index bf59e8637..1d29307ca 100644 --- a/cw_bitcoin/lib/bitcoin_wallet.dart +++ b/cw_bitcoin/lib/bitcoin_wallet.dart @@ -12,6 +12,7 @@ import 'package:cw_core/wallet_info.dart'; import 'package:cw_bitcoin/bitcoin_address_record.dart'; import 'package:cw_bitcoin/electrum_balance.dart'; import 'package:cw_bitcoin/bitcoin_wallet_addresses.dart'; +import 'package:bip39/bip39.dart' as bip39; part 'bitcoin_wallet.g.dart'; @@ -30,8 +31,10 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { ElectrumBalance? initialBalance, Map? initialRegularAddressIndex, Map? initialChangeAddressIndex, + String? passphrase, }) : super( mnemonic: mnemonic, + passphrase: passphrase, password: password, walletInfo: walletInfo, unspentCoinsInfo: unspentCoinsInfo, @@ -44,14 +47,19 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { initialBalance: initialBalance, seedBytes: seedBytes, currency: CryptoCurrency.btc) { + // in a standard BIP44 wallet, mainHd derivation path = m/84'/0'/0'/0 (account 0, index unspecified here) + // the sideHd derivation path = m/84'/0'/0'/1 (account 1, index unspecified here) + String derivationPath = walletInfo.derivationInfo!.derivationPath!; + String sideDerivationPath = derivationPath.substring(0, derivationPath.length - 1) + "1"; + final hd = bitcoin.HDWallet.fromSeed(seedBytes, network: networkType); walletAddresses = BitcoinWalletAddresses( walletInfo, electrumClient: electrumClient, initialAddresses: initialAddresses, initialRegularAddressIndex: initialRegularAddressIndex, initialChangeAddressIndex: initialChangeAddressIndex, - mainHd: hd, - sideHd: bitcoin.HDWallet.fromSeed(seedBytes, network: networkType).derivePath("m/0'/1"), + mainHd: hd.derivePath(derivationPath), + sideHd: hd.derivePath(sideDerivationPath), network: networkParam ?? network, ); autorun((_) { @@ -64,6 +72,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { required String password, required WalletInfo walletInfo, required Box unspentCoinsInfo, + String? passphrase, String? addressPageType, BasedUtxoNetwork? network, List? initialAddresses, @@ -71,14 +80,29 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { Map? initialRegularAddressIndex, Map? initialChangeAddressIndex, }) async { + late Uint8List seedBytes; + + switch (walletInfo.derivationInfo?.derivationType) { + case DerivationType.bip39: + seedBytes = await bip39.mnemonicToSeed( + mnemonic, + passphrase: passphrase ?? "", + ); + break; + case DerivationType.electrum: + default: + seedBytes = await mnemonicToSeedBytes(mnemonic); + break; + } return BitcoinWallet( mnemonic: mnemonic, + passphrase: passphrase ?? "", password: password, walletInfo: walletInfo, unspentCoinsInfo: unspentCoinsInfo, initialAddresses: initialAddresses, initialBalance: initialBalance, - seedBytes: await mnemonicToSeedBytes(mnemonic), + seedBytes: seedBytes, initialRegularAddressIndex: initialRegularAddressIndex, initialChangeAddressIndex: initialChangeAddressIndex, addressPageType: addressPageType, @@ -97,14 +121,38 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { : BitcoinNetwork.mainnet; final snp = await ElectrumWalletSnapshot.load(name, walletInfo.type, password, network); + walletInfo.derivationInfo ??= DerivationInfo( + derivationType: snp.derivationType ?? DerivationType.electrum, + derivationPath: snp.derivationPath, + ); + + // set the default if not present: + walletInfo.derivationInfo!.derivationPath = snp.derivationPath ?? "m/0'/1"; + + late Uint8List seedBytes; + + switch (walletInfo.derivationInfo!.derivationType) { + case DerivationType.electrum: + seedBytes = await mnemonicToSeedBytes(snp.mnemonic); + break; + case DerivationType.bip39: + default: + seedBytes = await bip39.mnemonicToSeed( + snp.mnemonic, + passphrase: snp.passphrase ?? '', + ); + break; + } + return BitcoinWallet( mnemonic: snp.mnemonic, password: password, + passphrase: snp.passphrase, walletInfo: walletInfo, unspentCoinsInfo: unspentCoinsInfo, initialAddresses: snp.addresses, initialBalance: snp.balance, - seedBytes: await mnemonicToSeedBytes(snp.mnemonic), + seedBytes: seedBytes, initialRegularAddressIndex: snp.regularAddressIndex, initialChangeAddressIndex: snp.changeAddressIndex, addressPageType: snp.addressPageType, diff --git a/cw_bitcoin/lib/bitcoin_wallet_creation_credentials.dart b/cw_bitcoin/lib/bitcoin_wallet_creation_credentials.dart index 37b272a1b..981c7a466 100644 --- a/cw_bitcoin/lib/bitcoin_wallet_creation_credentials.dart +++ b/cw_bitcoin/lib/bitcoin_wallet_creation_credentials.dart @@ -2,14 +2,35 @@ import 'package:cw_core/wallet_credentials.dart'; import 'package:cw_core/wallet_info.dart'; class BitcoinNewWalletCredentials extends WalletCredentials { - BitcoinNewWalletCredentials({required String name, WalletInfo? walletInfo}) - : super(name: name, walletInfo: walletInfo); + BitcoinNewWalletCredentials( + {required String name, + WalletInfo? walletInfo, + DerivationType? derivationType, + String? derivationPath}) + : super( + name: name, + walletInfo: walletInfo, + ); } class BitcoinRestoreWalletFromSeedCredentials extends WalletCredentials { - BitcoinRestoreWalletFromSeedCredentials( - {required String name, required String password, required this.mnemonic, WalletInfo? walletInfo}) - : super(name: name, password: password, walletInfo: walletInfo); + BitcoinRestoreWalletFromSeedCredentials({ + required String name, + required String password, + required this.mnemonic, + WalletInfo? walletInfo, + required DerivationType derivationType, + required String derivationPath, + String? passphrase, + }) : super( + name: name, + password: password, + passphrase: passphrase, + walletInfo: walletInfo, + derivationInfo: DerivationInfo( + derivationType: derivationType, + derivationPath: derivationPath, + )); final String mnemonic; } @@ -20,4 +41,4 @@ class BitcoinRestoreWalletFromWIFCredentials extends WalletCredentials { : super(name: name, password: password, walletInfo: walletInfo); final String wif; -} \ No newline at end of file +} diff --git a/cw_bitcoin/lib/bitcoin_wallet_service.dart b/cw_bitcoin/lib/bitcoin_wallet_service.dart index 38e769d15..e0548771b 100644 --- a/cw_bitcoin/lib/bitcoin_wallet_service.dart +++ b/cw_bitcoin/lib/bitcoin_wallet_service.dart @@ -12,6 +12,7 @@ import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:hive/hive.dart'; import 'package:collection/collection.dart'; +import 'package:bip39/bip39.dart' as bip39; class BitcoinWalletService extends WalletService { @@ -29,8 +30,9 @@ class BitcoinWalletService extends WalletService restoreFromSeed(BitcoinRestoreWalletFromSeedCredentials credentials, {bool? isTestnet}) async { - if (!validateMnemonic(credentials.mnemonic)) { + if (!validateMnemonic(credentials.mnemonic) && !bip39.validateMnemonic(credentials.mnemonic)) { throw BitcoinMnemonicIsIncorrectException(); } @@ -114,6 +116,7 @@ class BitcoinWalletService extends WalletService> electrum_derivations = { + DerivationType.electrum: [ + DerivationInfo( + derivationType: DerivationType.electrum, + derivationPath: "m/0'/0", + description: "Electrum", + scriptType: "p2wpkh", + ), + ], + DerivationType.bip39: [ + DerivationInfo( + derivationType: DerivationType.bip39, + derivationPath: "m/44'/0'/0'", + description: "Standard BIP44", + scriptType: "p2pkh", + ), + DerivationInfo( + derivationType: DerivationType.bip39, + derivationPath: "m/49'/0'/0'", + description: "Standard BIP49 compatibility segwit", + scriptType: "p2wpkh-p2sh", + ), + DerivationInfo( + derivationType: DerivationType.bip39, + derivationPath: "m/84'/0'/0'", + description: "Standard BIP84 native segwit", + scriptType: "p2wpkh", + ), + DerivationInfo( + derivationType: DerivationType.bip39, + derivationPath: "m/0'", + description: "Non-standard legacy", + scriptType: "p2pkh", + ), + DerivationInfo( + derivationType: DerivationType.bip39, + derivationPath: "m/0'", + description: "Non-standard compatibility segwit", + scriptType: "p2wpkh-p2sh", + ), + DerivationInfo( + derivationType: DerivationType.bip39, + derivationPath: "m/0'", + description: "Non-standard native segwit", + scriptType: "p2wpkh", + ), + DerivationInfo( + derivationType: DerivationType.bip39, + derivationPath: "m/44'/0'/0'", + description: "Samourai Deposit", + scriptType: "p2wpkh", + ), + DerivationInfo( + derivationType: DerivationType.bip39, + derivationPath: "m/49'/0'/0'", + description: "Samourai Deposit", + scriptType: "p2wpkh", + ), + DerivationInfo( + derivationType: DerivationType.bip39, + derivationPath: "m/84'/0'/2147483644'", + description: "Samourai Bad Bank (toxic change)", + scriptType: "p2wpkh", + ), + DerivationInfo( + derivationType: DerivationType.bip39, + derivationPath: "m/84'/0'/2147483645'", + description: "Samourai Whirlpool Pre Mix", + scriptType: "p2wpkh", + ), + DerivationInfo( + derivationType: DerivationType.bip39, + derivationPath: "m/84'/0'/2147483646'", + description: "Samourai Whirlpool Post Mix", + scriptType: "p2wpkh", + ), + DerivationInfo( + derivationType: DerivationType.bip39, + derivationPath: "m/44'/0'/2147483647'", + description: "Samourai Ricochet legacy", + scriptType: "p2pkh", + ), + DerivationInfo( + derivationType: DerivationType.bip39, + derivationPath: "m/49'/0'/2147483647'", + description: "Samourai Ricochet compatibility segwit", + scriptType: "p2wpkh-p2sh", + ), + DerivationInfo( + derivationType: DerivationType.bip39, + derivationPath: "m/84'/0'/2147483647'", + description: "Samourai Ricochet native segwit", + scriptType: "p2wpkh", + ), + DerivationInfo( + derivationType: DerivationType.bip39, + derivationPath: "m/84'/2'/0'", + description: "Default Litecoin", + scriptType: "p2wpkh", + ), + ], +}; diff --git a/cw_bitcoin/lib/electrum_wallet.dart b/cw_bitcoin/lib/electrum_wallet.dart index 4a76ee5dd..8342e4816 100644 --- a/cw_bitcoin/lib/electrum_wallet.dart +++ b/cw_bitcoin/lib/electrum_wallet.dart @@ -55,13 +55,15 @@ abstract class ElectrumWalletBase required this.networkType, required this.mnemonic, required Uint8List seedBytes, + this.passphrase, List? initialAddresses, ElectrumClient? electrumClient, ElectrumBalance? initialBalance, CryptoCurrency? currency}) : hd = currency == CryptoCurrency.bch ? bitcoinCashHDWallet(seedBytes) - : bitcoin.HDWallet.fromSeed(seedBytes, network: networkType).derivePath("m/0'/0"), + : bitcoin.HDWallet.fromSeed(seedBytes, network: networkType) + .derivePath(walletInfo.derivationInfo?.derivationPath ?? "m/0'/0"), syncStatus = NotConnectedSyncStatus(), _password = password, _feeRates = [], @@ -92,6 +94,7 @@ abstract class ElectrumWalletBase final bitcoin.HDWallet hd; final String mnemonic; + final String? passphrase; @override @observable @@ -617,6 +620,7 @@ abstract class ElectrumWalletBase String toJSON() => json.encode({ 'mnemonic': mnemonic, + 'passphrase': passphrase ?? '', 'account_index': walletAddresses.currentReceiveAddressIndexByType, 'change_address_index': walletAddresses.currentChangeAddressIndexByType, 'addresses': walletAddresses.allAddresses.map((addr) => addr.toJSON()).toList(), @@ -624,6 +628,8 @@ abstract class ElectrumWalletBase ? SegwitAddresType.p2wpkh.toString() : walletInfo.addressPageType.toString(), 'balance': balance[currency]?.toJSON(), + 'derivationTypeIndex': walletInfo.derivationInfo?.derivationType?.index, + 'derivationPath': walletInfo.derivationInfo?.derivationPath, }); int feeRate(TransactionPriority priority) { diff --git a/cw_bitcoin/lib/electrum_wallet_snapshot.dart b/cw_bitcoin/lib/electrum_wallet_snapshot.dart index 6f76ab312..218792e3c 100644 --- a/cw_bitcoin/lib/electrum_wallet_snapshot.dart +++ b/cw_bitcoin/lib/electrum_wallet_snapshot.dart @@ -3,6 +3,7 @@ import 'package:bitcoin_base/bitcoin_base.dart'; import 'package:cw_bitcoin/bitcoin_address_record.dart'; import 'package:cw_bitcoin/electrum_balance.dart'; import 'package:cw_core/pathForWallet.dart'; +import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/utils/file.dart'; import 'package:cw_core/wallet_type.dart'; @@ -17,6 +18,9 @@ class ElectrumWalletSnapshot { required this.regularAddressIndex, required this.changeAddressIndex, required this.addressPageType, + this.passphrase, + this.derivationType, + this.derivationPath, }); final String name; @@ -29,6 +33,9 @@ class ElectrumWalletSnapshot { ElectrumBalance balance; Map regularAddressIndex; Map changeAddressIndex; + String? passphrase; + DerivationType? derivationType; + String? derivationPath; static Future load( String name, WalletType type, String password, BasedUtxoNetwork network) async { @@ -37,6 +44,7 @@ class ElectrumWalletSnapshot { final data = json.decode(jsonSource) as Map; final addressesTmp = data['addresses'] as List? ?? []; final mnemonic = data['mnemonic'] as String; + final passphrase = data['passphrase'] as String? ?? ''; final addresses = addressesTmp .whereType() .map((addr) => BitcoinAddressRecord.fromJSON(addr, network)) @@ -46,6 +54,10 @@ class ElectrumWalletSnapshot { var regularAddressIndexByType = {SegwitAddresType.p2wpkh.toString(): 0}; var changeAddressIndexByType = {SegwitAddresType.p2wpkh.toString(): 0}; + final derivationType = + DerivationType.values[(data['derivationTypeIndex'] as int?) ?? DerivationType.electrum.index]; + final derivationPath = data['derivationPath'] as String? ?? "m/0'/0"; + try { regularAddressIndexByType = { SegwitAddresType.p2wpkh.toString(): int.parse(data['account_index'] as String? ?? '0') @@ -65,12 +77,15 @@ class ElectrumWalletSnapshot { name: name, type: type, password: password, + passphrase: passphrase, mnemonic: mnemonic, addresses: addresses, balance: balance, regularAddressIndex: regularAddressIndexByType, changeAddressIndex: changeAddressIndexByType, addressPageType: data['address_page_type'] as String?, + derivationType: derivationType, + derivationPath: derivationPath, ); } } diff --git a/cw_bitcoin/lib/litecoin_wallet.dart b/cw_bitcoin/lib/litecoin_wallet.dart index d2379d5a5..4d166e47b 100644 --- a/cw_bitcoin/lib/litecoin_wallet.dart +++ b/cw_bitcoin/lib/litecoin_wallet.dart @@ -15,6 +15,7 @@ import 'package:cw_bitcoin/bitcoin_address_record.dart'; import 'package:cw_bitcoin/electrum_balance.dart'; import 'package:cw_bitcoin/litecoin_network.dart'; import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin; +import 'package:bip39/bip39.dart' as bip39; part 'litecoin_wallet.g.dart'; @@ -62,11 +63,26 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { required String password, required WalletInfo walletInfo, required Box unspentCoinsInfo, + String? passphrase, String? addressPageType, List? initialAddresses, ElectrumBalance? initialBalance, Map? initialRegularAddressIndex, Map? initialChangeAddressIndex}) async { + late Uint8List seedBytes; + + switch (walletInfo.derivationInfo?.derivationType) { + case DerivationType.bip39: + seedBytes = await bip39.mnemonicToSeed( + mnemonic, + passphrase: passphrase ?? "", + ); + break; + case DerivationType.electrum: + default: + seedBytes = await mnemonicToSeedBytes(mnemonic); + break; + } return LitecoinWallet( mnemonic: mnemonic, password: password, @@ -74,7 +90,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { unspentCoinsInfo: unspentCoinsInfo, initialAddresses: initialAddresses, initialBalance: initialBalance, - seedBytes: await mnemonicToSeedBytes(mnemonic), + seedBytes: seedBytes, initialRegularAddressIndex: initialRegularAddressIndex, initialChangeAddressIndex: initialChangeAddressIndex, addressPageType: addressPageType, diff --git a/cw_bitcoin/lib/litecoin_wallet_service.dart b/cw_bitcoin/lib/litecoin_wallet_service.dart index ee3b0e628..9143556ab 100644 --- a/cw_bitcoin/lib/litecoin_wallet_service.dart +++ b/cw_bitcoin/lib/litecoin_wallet_service.dart @@ -11,6 +11,7 @@ import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:collection/collection.dart'; +import 'package:bip39/bip39.dart' as bip39; class LitecoinWalletService extends WalletService< BitcoinNewWalletCredentials, @@ -27,8 +28,9 @@ class LitecoinWalletService extends WalletService< @override Future create(BitcoinNewWalletCredentials credentials, {bool? isTestnet}) async { final wallet = await LitecoinWalletBase.create( - mnemonic: await generateMnemonic(), + mnemonic: await generateElectrumMnemonic(), password: credentials.password!, + passphrase: credentials.passphrase, walletInfo: credentials.walletInfo!, unspentCoinsInfo: unspentCoinsInfoSource); await wallet.save(); @@ -100,12 +102,13 @@ class LitecoinWalletService extends WalletService< @override Future restoreFromSeed( BitcoinRestoreWalletFromSeedCredentials credentials, {bool? isTestnet}) async { - if (!validateMnemonic(credentials.mnemonic)) { + if (!validateMnemonic(credentials.mnemonic) && !bip39.validateMnemonic(credentials.mnemonic)) { throw LitecoinMnemonicIsIncorrectException(); } final wallet = await LitecoinWalletBase.create( password: credentials.password!, + passphrase: credentials.passphrase, mnemonic: credentials.mnemonic, walletInfo: credentials.walletInfo!, unspentCoinsInfo: unspentCoinsInfoSource); diff --git a/cw_bitcoin/lib/utils.dart b/cw_bitcoin/lib/utils.dart index b156ccba3..b3707e764 100644 --- a/cw_bitcoin/lib/utils.dart +++ b/cw_bitcoin/lib/utils.dart @@ -5,29 +5,58 @@ import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin; import 'package:bitcoin_flutter/src/payments/index.dart' show PaymentData; import 'package:hex/hex.dart'; -bitcoin.PaymentData generatePaymentData({required bitcoin.HDWallet hd, required int index}) => - PaymentData(pubkey: Uint8List.fromList(HEX.decode(hd.derive(index).pubKey!))); +bitcoin.PaymentData generatePaymentData({required bitcoin.HDWallet hd, int? index}) { + final pubKey = index != null ? hd.derive(index).pubKey! : hd.pubKey!; + return PaymentData(pubkey: Uint8List.fromList(HEX.decode(pubKey))); +} ECPrivate generateECPrivate( - {required bitcoin.HDWallet hd, required int index, required BasedUtxoNetwork network}) => - ECPrivate.fromWif(hd.derive(index).wif!, netVersion: network.wifNetVer); + {required bitcoin.HDWallet hd, required BasedUtxoNetwork network, int? index}) { + final wif = index != null ? hd.derive(index).wif! : hd.wif!; + return ECPrivate.fromWif(wif, netVersion: network.wifNetVer); +} -String generateP2WPKHAddress( - {required bitcoin.HDWallet hd, required int index, required BasedUtxoNetwork network}) => - ECPublic.fromHex(hd.derive(index).pubKey!).toP2wpkhAddress().toAddress(network); +String generateP2WPKHAddress({ + required bitcoin.HDWallet hd, + required BasedUtxoNetwork network, + int? index, +}) { + final pubKey = index != null ? hd.derive(index).pubKey! : hd.pubKey!; + return ECPublic.fromHex(pubKey).toP2wpkhAddress().toAddress(network); +} -String generateP2SHAddress( - {required bitcoin.HDWallet hd, required int index, required BasedUtxoNetwork network}) => - ECPublic.fromHex(hd.derive(index).pubKey!).toP2wpkhInP2sh().toAddress(network); +String generateP2SHAddress({ + required bitcoin.HDWallet hd, + required BasedUtxoNetwork network, + int? index, +}) { + final pubKey = index != null ? hd.derive(index).pubKey! : hd.pubKey!; + return ECPublic.fromHex(pubKey).toP2wpkhInP2sh().toAddress(network); +} -String generateP2WSHAddress( - {required bitcoin.HDWallet hd, required int index, required BasedUtxoNetwork network}) => - ECPublic.fromHex(hd.derive(index).pubKey!).toP2wshAddress().toAddress(network); +String generateP2WSHAddress({ + required bitcoin.HDWallet hd, + required BasedUtxoNetwork network, + int? index, +}) { + final pubKey = index != null ? hd.derive(index).pubKey! : hd.pubKey!; + return ECPublic.fromHex(pubKey).toP2wshAddress().toAddress(network); +} -String generateP2PKHAddress( - {required bitcoin.HDWallet hd, required int index, required BasedUtxoNetwork network}) => - ECPublic.fromHex(hd.derive(index).pubKey!).toP2pkhAddress().toAddress(network); +String generateP2PKHAddress({ + required bitcoin.HDWallet hd, + required BasedUtxoNetwork network, + int? index, +}) { + final pubKey = index != null ? hd.derive(index).pubKey! : hd.pubKey!; + return ECPublic.fromHex(pubKey).toP2pkhAddress().toAddress(network); +} -String generateP2TRAddress( - {required bitcoin.HDWallet hd, required int index, required BasedUtxoNetwork network}) => - ECPublic.fromHex(hd.derive(index).pubKey!).toTaprootAddress().toAddress(network); +String generateP2TRAddress({ + required bitcoin.HDWallet hd, + required BasedUtxoNetwork network, + int? index, +}) { + final pubKey = index != null ? hd.derive(index).pubKey! : hd.pubKey!; + return ECPublic.fromHex(pubKey).toTaprootAddress().toAddress(network); +} diff --git a/cw_bitcoin/pubspec.lock b/cw_bitcoin/pubspec.lock index 50cd432c0..86d58b9b1 100644 --- a/cw_bitcoin/pubspec.lock +++ b/cw_bitcoin/pubspec.lock @@ -217,10 +217,10 @@ packages: dependency: transitive description: name: collection - sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 + sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" url: "https://pub.dev" source: hosted - version: "1.17.2" + version: "1.17.1" convert: dependency: transitive description: @@ -434,18 +434,18 @@ packages: dependency: transitive description: name: matcher - sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" url: "https://pub.dev" source: hosted - version: "0.12.16" + version: "0.12.15" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.2.0" meta: dependency: transitive description: @@ -663,10 +663,10 @@ packages: dependency: transitive description: name: source_span - sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.9.1" stack_trace: dependency: transitive description: @@ -711,10 +711,10 @@ packages: dependency: transitive description: name: test_api - sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" + sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb url: "https://pub.dev" source: hosted - version: "0.6.0" + version: "0.5.1" timing: dependency: transitive description: @@ -748,21 +748,13 @@ packages: source: hosted version: "2.1.4" watcher: - dependency: "direct overridden" + dependency: transitive description: name: watcher sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" url: "https://pub.dev" source: hosted version: "1.1.0" - web: - dependency: transitive - description: - name: web - sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 - url: "https://pub.dev" - source: hosted - version: "0.1.4-beta" web_socket_channel: dependency: transitive description: @@ -796,5 +788,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.1.0-185.0.dev <4.0.0" + dart: ">=3.0.0 <4.0.0" flutter: ">=3.10.0" diff --git a/cw_core/lib/hive_type_ids.dart b/cw_core/lib/hive_type_ids.dart index 3fa2eb647..e0896bab1 100644 --- a/cw_core/lib/hive_type_ids.dart +++ b/cw_core/lib/hive_type_ids.dart @@ -14,4 +14,5 @@ const ERC20_TOKEN_TYPE_ID = 12; const NANO_ACCOUNT_TYPE_ID = 13; const POW_NODE_TYPE_ID = 14; const DERIVATION_TYPE_TYPE_ID = 15; -const SPL_TOKEN_TYPE_ID = 16; +const SPL_TOKEN_TYPE_ID = 16; +const DERIVATION_INFO_TYPE_ID = 17; diff --git a/cw_core/lib/wallet_credentials.dart b/cw_core/lib/wallet_credentials.dart index 4d5f331c9..9b28680f9 100644 --- a/cw_core/lib/wallet_credentials.dart +++ b/cw_core/lib/wallet_credentials.dart @@ -7,15 +7,19 @@ abstract class WalletCredentials { this.seedPhraseLength, this.walletInfo, this.password, - this.derivationType, - this.derivationPath, - }); + this.passphrase, + this.derivationInfo, + }) { + if (this.walletInfo != null && derivationInfo != null) { + this.walletInfo!.derivationInfo = derivationInfo; + } + } final String name; final int? height; int? seedPhraseLength; String? password; - DerivationType? derivationType; - String? derivationPath; + String? passphrase; WalletInfo? walletInfo; + DerivationInfo? derivationInfo; } diff --git a/cw_core/lib/wallet_info.dart b/cw_core/lib/wallet_info.dart index 2a44175a7..4892f6d1d 100644 --- a/cw_core/lib/wallet_info.dart +++ b/cw_core/lib/wallet_info.dart @@ -17,28 +17,42 @@ enum DerivationType { @HiveField(3) bip39, @HiveField(4) - electrum1, - @HiveField(5) - electrum2, + electrum, } -class DerivationInfo { +@HiveType(typeId: DerivationInfo.typeId) +class DerivationInfo extends HiveObject { DerivationInfo({ - required this.derivationType, + this.derivationType, this.derivationPath, this.balance = "", this.address = "", - this.height = 0, - this.script_type, + this.transactionsCount = 0, + this.scriptType, this.description, }); - String balance; + static const typeId = DERIVATION_INFO_TYPE_ID; + + @HiveField(0, defaultValue: '') String address; - int height; - final DerivationType derivationType; - final String? derivationPath; - final String? script_type; + + @HiveField(1, defaultValue: '') + String balance; + + @HiveField(2) + int transactionsCount; + + @HiveField(3) + DerivationType? derivationType; + + @HiveField(4) + String? derivationPath; + + @HiveField(5) + final String? scriptType; + + @HiveField(6) final String? description; } @@ -57,8 +71,7 @@ class WalletInfo extends HiveObject { this.yatEid, this.yatLastUsedAddressRaw, this.showIntroCakePayCard, - this.derivationType, - this.derivationPath) + this.derivationInfo) : _yatLastUsedAddressController = StreamController.broadcast(); factory WalletInfo.external({ @@ -74,24 +87,23 @@ class WalletInfo extends HiveObject { bool? showIntroCakePayCard, String yatEid = '', String yatLastUsedAddressRaw = '', - DerivationType? derivationType, - String? derivationPath, + DerivationInfo? derivationInfo, }) { return WalletInfo( - id, - name, - type, - isRecovery, - restoreHeight, - date.millisecondsSinceEpoch, - dirPath, - path, - address, - yatEid, - yatLastUsedAddressRaw, - showIntroCakePayCard, - derivationType, - derivationPath); + id, + name, + type, + isRecovery, + restoreHeight, + date.millisecondsSinceEpoch, + dirPath, + path, + address, + yatEid, + yatLastUsedAddressRaw, + showIntroCakePayCard, + derivationInfo, + ); } static const typeId = WALLET_INFO_TYPE_ID; @@ -143,10 +155,10 @@ class WalletInfo extends HiveObject { List? usedAddresses; @HiveField(16) - DerivationType? derivationType; + DerivationType? derivationType; // no longer used @HiveField(17) - String? derivationPath; + String? derivationPath; // no longer used @HiveField(18) String? addressPageType; @@ -154,6 +166,9 @@ class WalletInfo extends HiveObject { @HiveField(19) String? network; + @HiveField(20) + DerivationInfo? derivationInfo; + String get yatLastUsedAddress => yatLastUsedAddressRaw ?? ''; set yatLastUsedAddress(String address) { diff --git a/cw_core/pubspec.lock b/cw_core/pubspec.lock index aef76f300..678e57b54 100644 --- a/cw_core/pubspec.lock +++ b/cw_core/pubspec.lock @@ -149,10 +149,10 @@ packages: dependency: transitive description: name: collection - sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 + sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" url: "https://pub.dev" source: hosted - version: "1.17.2" + version: "1.17.1" convert: dependency: transitive description: @@ -343,18 +343,18 @@ packages: dependency: transitive description: name: matcher - sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" url: "https://pub.dev" source: hosted - version: "0.12.16" + version: "0.12.15" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.2.0" meta: dependency: transitive description: @@ -564,10 +564,10 @@ packages: dependency: transitive description: name: source_span - sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.9.1" stack_trace: dependency: transitive description: @@ -612,10 +612,10 @@ packages: dependency: transitive description: name: test_api - sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" + sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb url: "https://pub.dev" source: hosted - version: "0.6.0" + version: "0.5.1" timing: dependency: transitive description: @@ -641,21 +641,13 @@ packages: source: hosted version: "2.1.4" watcher: - dependency: "direct overridden" + dependency: transitive description: name: watcher sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" url: "https://pub.dev" source: hosted version: "1.1.0" - web: - dependency: transitive - description: - name: web - sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 - url: "https://pub.dev" - source: hosted - version: "0.1.4-beta" web_socket_channel: dependency: transitive description: @@ -689,5 +681,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.1.0-185.0.dev <4.0.0" + dart: ">=3.0.0 <4.0.0" flutter: ">=3.10.0" diff --git a/cw_nano/lib/nano_wallet.dart b/cw_nano/lib/nano_wallet.dart index 265f78eb7..5efe3006d 100644 --- a/cw_nano/lib/nano_wallet.dart +++ b/cw_nano/lib/nano_wallet.dart @@ -43,7 +43,7 @@ abstract class NanoWalletBase }) : syncStatus = NotConnectedSyncStatus(), _password = password, _mnemonic = mnemonic, - _derivationType = walletInfo.derivationType!, + _derivationType = walletInfo.derivationInfo!.derivationType!, _isTransactionUpdating = false, _client = NanoClient(), walletAddresses = NanoWalletAddresses(walletInfo), @@ -389,7 +389,10 @@ abstract class NanoWalletBase derivationType = DerivationType.bip39; } - walletInfo.derivationType = derivationType; + walletInfo.derivationInfo ??= DerivationInfo(derivationType: derivationType); + if (walletInfo.derivationInfo!.derivationType == null) { + walletInfo.derivationInfo!.derivationType = derivationType; + } return NanoWallet( walletInfo: walletInfo, diff --git a/cw_nano/lib/nano_wallet_creation_credentials.dart b/cw_nano/lib/nano_wallet_creation_credentials.dart index 3616fcf44..4ee79ce48 100644 --- a/cw_nano/lib/nano_wallet_creation_credentials.dart +++ b/cw_nano/lib/nano_wallet_creation_credentials.dart @@ -2,8 +2,15 @@ import 'package:cw_core/wallet_credentials.dart'; import 'package:cw_core/wallet_info.dart'; class NanoNewWalletCredentials extends WalletCredentials { - NanoNewWalletCredentials({required String name, String? password}) - : super(name: name, password: password); + NanoNewWalletCredentials({ + required String name, + String? password, + DerivationType? derivationType, + }) : super( + name: name, + password: password, + derivationInfo: DerivationInfo(derivationType: derivationType), + ); } class NanoRestoreWalletFromSeedCredentials extends WalletCredentials { @@ -11,11 +18,11 @@ class NanoRestoreWalletFromSeedCredentials extends WalletCredentials { required String name, required this.mnemonic, String? password, - DerivationType? derivationType, + required DerivationType derivationType, }) : super( name: name, password: password, - derivationType: derivationType, + derivationInfo: DerivationInfo(derivationType: derivationType), ); final String mnemonic; @@ -30,12 +37,12 @@ class NanoRestoreWalletFromKeysCredentials extends WalletCredentials { NanoRestoreWalletFromKeysCredentials({ required String name, required String password, + required DerivationType derivationType, required this.seedKey, - DerivationType? derivationType, }) : super( name: name, password: password, - derivationType: derivationType, + derivationInfo: DerivationInfo(derivationType: derivationType), ); final String seedKey; diff --git a/cw_nano/lib/nano_wallet_service.dart b/cw_nano/lib/nano_wallet_service.dart index 7ab502d49..b1497a625 100644 --- a/cw_nano/lib/nano_wallet_service.dart +++ b/cw_nano/lib/nano_wallet_service.dart @@ -28,11 +28,11 @@ class NanoWalletService extends WalletService create(NanoNewWalletCredentials credentials, {bool? isTestnet}) async { // nano standard: - DerivationType derivationType = DerivationType.nano; String seedKey = NanoSeeds.generateSeed(); String mnemonic = NanoDerivations.standardSeedToMnemonic(seedKey); - credentials.walletInfo!.derivationType = derivationType; + // ensure default if not present: + credentials.walletInfo!.derivationInfo ??= DerivationInfo(derivationType: DerivationType.nano); final wallet = NanoWallet( walletInfo: credentials.walletInfo!, @@ -88,9 +88,6 @@ class NanoWalletService extends WalletService BitcoinTransactionPriority.medium; - - @override - WalletCredentials createBitcoinRestoreWalletFromSeedCredentials( - {required String name, required String mnemonic, required String password}) => - BitcoinRestoreWalletFromSeedCredentials(name: name, mnemonic: mnemonic, password: password); + WalletCredentials createBitcoinRestoreWalletFromSeedCredentials({ + required String name, + required String mnemonic, + required String password, + required DerivationType derivationType, + required String derivationPath, + String? passphrase, + }) => + BitcoinRestoreWalletFromSeedCredentials( + name: name, + mnemonic: mnemonic, + password: password, + derivationType: derivationType, + derivationPath: derivationPath, + passphrase: passphrase, + ); @override WalletCredentials createBitcoinRestoreWalletFromWIFCredentials( @@ -23,6 +32,9 @@ class CWBitcoin extends Bitcoin { {required String name, WalletInfo? walletInfo}) => BitcoinNewWalletCredentials(name: name, walletInfo: walletInfo); + @override + TransactionPriority getMediumTransactionPriority() => BitcoinTransactionPriority.medium; + @override List getWordList() => wordlist; @@ -78,21 +90,20 @@ class CWBitcoin extends Bitcoin { final bitcoinFeeRate = priority == BitcoinTransactionPriority.custom && feeRate != null ? feeRate : null; return BitcoinTransactionCredentials( - outputs - .map((out) => OutputInfo( - fiatAmount: out.fiatAmount, - cryptoAmount: out.cryptoAmount, - address: out.address, - note: out.note, - sendAll: out.sendAll, - extractedAddress: out.extractedAddress, - isParsedAddress: out.isParsedAddress, - formattedCryptoAmount: out.formattedCryptoAmount, - memo: out.memo)) - .toList(), - priority: priority as BitcoinTransactionPriority, - feeRate: bitcoinFeeRate - ); + outputs + .map((out) => OutputInfo( + fiatAmount: out.fiatAmount, + cryptoAmount: out.cryptoAmount, + address: out.address, + note: out.note, + sendAll: out.sendAll, + extractedAddress: out.extractedAddress, + isParsedAddress: out.isParsedAddress, + formattedCryptoAmount: out.formattedCryptoAmount, + memo: out.memo)) + .toList(), + priority: priority as BitcoinTransactionPriority, + feeRate: bitcoinFeeRate); } @override @@ -248,6 +259,137 @@ class CWBitcoin extends Bitcoin { } } + @override + Future> compareDerivationMethods( + {required String mnemonic, required Node node}) async { + if (await checkIfMnemonicIsElectrum2(mnemonic)) { + return [DerivationType.electrum]; + } + + return [DerivationType.bip39, DerivationType.electrum]; + } + + int _countOccurrences(String str, String charToCount) { + int count = 0; + for (int i = 0; i < str.length; i++) { + if (str[i] == charToCount) { + count++; + } + } + return count; + } + + @override + Future> getDerivationsFromMnemonic({ + required String mnemonic, + required Node node, + String? passphrase, + }) async { + List list = []; + + List types = await compareDerivationMethods(mnemonic: mnemonic, node: node); + if (types.length == 1 && types.first == DerivationType.electrum) { + return [ + DerivationInfo( + derivationType: DerivationType.electrum, + derivationPath: "m/0'/0", + description: "Electrum", + scriptType: "p2wpkh", + ) + ]; + } + + final electrumClient = ElectrumClient(); + await electrumClient.connectToUri(node.uri); + + late BasedUtxoNetwork network; + btc.NetworkType networkType; + switch (node.type) { + case WalletType.litecoin: + network = LitecoinNetwork.mainnet; + networkType = litecoinNetwork; + break; + case WalletType.bitcoin: + default: + network = BitcoinNetwork.mainnet; + networkType = btc.bitcoin; + break; + } + + for (DerivationType dType in electrum_derivations.keys) { + late Uint8List seedBytes; + if (dType == DerivationType.electrum) { + seedBytes = await mnemonicToSeedBytes(mnemonic); + } else if (dType == DerivationType.bip39) { + seedBytes = bip39.mnemonicToSeed(mnemonic, passphrase: passphrase ?? ''); + } + + for (DerivationInfo dInfo in electrum_derivations[dType]!) { + try { + DerivationInfo dInfoCopy = DerivationInfo( + derivationType: dInfo.derivationType, + derivationPath: dInfo.derivationPath, + description: dInfo.description, + scriptType: dInfo.scriptType, + ); + + String derivationPath = dInfoCopy.derivationPath!; + int derivationDepth = _countOccurrences(derivationPath, "/"); + + // the correct derivation depth is dependant on the derivation type: + // the derivation paths defined in electrum_derivations are at the ROOT level, i.e.: + // electrum's format doesn't specify subaddresses, just subaccounts: + + // for BIP44 + if (derivationDepth == 3) { + // we add "/0/0" so that we generate account 0, index 0 and correctly get balance + derivationPath += "/0/0"; + // we don't support sub-ACCOUNTS in bitcoin like we do monero, and so the path dInfoCopy + // expects should be ACCOUNT 0, index unspecified: + dInfoCopy.derivationPath = dInfoCopy.derivationPath! + "/0"; + } + + // var hd = bip32.BIP32.fromSeed(seedBytes).derivePath(derivationPath); + final hd = btc.HDWallet.fromSeed( + seedBytes, + network: networkType, + ).derivePath(derivationPath); + + String? address; + switch (dInfoCopy.scriptType) { + case "p2wpkh": + address = generateP2WPKHAddress(hd: hd, network: network); + break; + case "p2pkh": + address = generateP2PKHAddress(hd: hd, network: network); + break; + case "p2wpkh-p2sh": + address = generateP2SHAddress(hd: hd, network: network); + break; + default: + continue; + } + + final sh = scriptHash(address, network: network); + final history = await electrumClient.getHistory(sh); + + final balance = await electrumClient.getBalance(sh); + dInfoCopy.balance = balance.entries.first.value.toString(); + dInfoCopy.address = address; + dInfoCopy.transactionsCount = history.length; + + list.add(dInfoCopy); + } catch (e) { + print(e); + } + } + } + + // sort the list such that derivations with the most transactions are first: + list.sort((a, b) => b.transactionsCount.compareTo(a.transactionsCount)); + return list; + } + @override bool hasTaprootInput(PendingTransaction pendingTransaction) { return (pendingTransaction as PendingBitcoinTransaction).hasTaprootInputs; diff --git a/lib/entities/default_settings_migration.dart b/lib/entities/default_settings_migration.dart index a0f570e95..99178c815 100644 --- a/lib/entities/default_settings_migration.dart +++ b/lib/entities/default_settings_migration.dart @@ -220,6 +220,10 @@ Future defaultSettingsMigration( await updateNanoNodeList(nodes: nodes); break; + case 32: + await updateBtcNanoWalletInfos(walletInfoSource); + break; + default: break; } @@ -756,6 +760,20 @@ Future changeDefaultMoneroNode( } } +Future updateBtcNanoWalletInfos(Box walletsInfoSource) async { + for (WalletInfo walletInfo in walletsInfoSource.values) { + if (walletInfo.type == WalletType.nano || walletInfo.type == WalletType.bitcoin) { + walletInfo.derivationInfo = DerivationInfo( + derivationPath: walletInfo.derivationPath, + derivationType: walletInfo.derivationType, + address: walletInfo.address, + transactionsCount: walletInfo.restoreHeight, + ); + await walletInfo.save(); + } + } +} + Future changeDefaultBitcoinNode( Box nodeSource, SharedPreferences sharedPreferences) async { const cakeWalletBitcoinNodeUriPattern = '.cakewallet.com'; diff --git a/lib/entities/parse_address_from_domain.dart b/lib/entities/parse_address_from_domain.dart index bab0ef51d..f729e6392 100644 --- a/lib/entities/parse_address_from_domain.dart +++ b/lib/entities/parse_address_from_domain.dart @@ -51,10 +51,12 @@ class AddressResolver { } final match = RegExp(addressPattern).firstMatch(raw); - return match?.group(0)?.replaceAllMapped(RegExp('[^0-9a-zA-Z]|bitcoincash:|nano_'), + return match?.group(0)?.replaceAllMapped(RegExp('[^0-9a-zA-Z]|bitcoincash:|nano_|ban_'), (Match match) { String group = match.group(0)!; - if (group.startsWith('bitcoincash:') || group.startsWith('nano_')) { + if (group.startsWith('bitcoincash:') || + group.startsWith('nano_') || + group.startsWith('ban_')) { return group; } return ''; diff --git a/lib/main.dart b/lib/main.dart index b80c9eb85..ff5b0e5c0 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -102,6 +102,10 @@ Future initializeAppConfigs() async { CakeHive.registerAdapter(DerivationTypeAdapter()); } + if (!CakeHive.isAdapterRegistered(DERIVATION_INFO_TYPE_ID)) { + CakeHive.registerAdapter(DerivationInfoAdapter()); + } + if (!CakeHive.isAdapterRegistered(WALLET_TYPE_TYPE_ID)) { CakeHive.registerAdapter(WalletTypeAdapter()); } @@ -163,7 +167,7 @@ Future initializeAppConfigs() async { transactionDescriptions: transactionDescriptions, secureStorage: secureStorage, anonpayInvoiceInfo: anonpayInvoiceInfo, - initialMigrationVersion: 31, + initialMigrationVersion: 32, ); } diff --git a/lib/nano/cw_nano.dart b/lib/nano/cw_nano.dart index 5896f7c26..13800cff6 100644 --- a/lib/nano/cw_nano.dart +++ b/lib/nano/cw_nano.dart @@ -96,6 +96,7 @@ class CWNano extends Nano { NanoNewWalletCredentials( name: name, password: password, + derivationType: DerivationType.nano, ); @override @@ -103,15 +104,10 @@ class CWNano extends Nano { required String name, required String password, required String mnemonic, - DerivationType? derivationType, + required DerivationType derivationType, }) { - if (derivationType == null) { - // figure out the derivation type as best we can, otherwise set it to "unknown" - if (mnemonic.split(" ").length == 12) { - derivationType = DerivationType.bip39; - } else { - derivationType = DerivationType.unknown; - } + if (mnemonic.split(" ").length == 12 && derivationType != DerivationType.bip39) { + throw Exception("Invalid mnemonic for derivation type!"); } return NanoRestoreWalletFromSeedCredentials( @@ -127,15 +123,10 @@ class CWNano extends Nano { required String name, required String password, required String seedKey, - DerivationType? derivationType, + required DerivationType derivationType, }) { - if (derivationType == null) { - // figure out the derivation type as best we can, otherwise set it to "unknown" - if (seedKey.length == 64) { - derivationType = DerivationType.nano; - } else { - derivationType = DerivationType.unknown; - } + if (seedKey.length == 128 && derivationType != DerivationType.bip39) { + throw Exception("Invalid seed key length for derivation type!"); } return NanoRestoreWalletFromKeysCredentials( @@ -199,7 +190,6 @@ class CWNano extends Nano { } class CWNanoUtil extends NanoUtil { - @override bool isValidBip39Seed(String seed) { return NanoDerivations.isValidBip39Seed(seed); @@ -353,4 +343,54 @@ class CWNanoUtil extends NanoUtil { return [DerivationType.nano, DerivationType.bip39]; } } + + @override + Future> getDerivationsFromMnemonic({ + String? mnemonic, + String? seedKey, + required Node node, + }) async { + List list = []; + + List possibleDerivationTypes = await compareDerivationMethods( + mnemonic: mnemonic, + privateKey: seedKey, + node: node, + ); + if (possibleDerivationTypes.length == 1) { + return [DerivationInfo(derivationType: possibleDerivationTypes.first)]; + } + + AccountInfoResponse? bip39Info = await nanoUtil!.getInfoFromSeedOrMnemonic( + DerivationType.bip39, + mnemonic: mnemonic, + seedKey: seedKey, + node: node, + ); + AccountInfoResponse? standardInfo = await nanoUtil!.getInfoFromSeedOrMnemonic( + DerivationType.nano, + mnemonic: mnemonic, + seedKey: seedKey, + node: node, + ); + + if (standardInfo?.confirmationHeight != null && standardInfo!.confirmationHeight > 0) { + list.add(DerivationInfo( + derivationType: DerivationType.nano, + balance: nanoUtil!.getRawAsUsableString(standardInfo.balance, nanoUtil!.rawPerNano), + address: standardInfo.address!, + transactionsCount: standardInfo.confirmationHeight, + )); + } + + if (bip39Info?.confirmationHeight != null && bip39Info!.confirmationHeight > 0) { + list.add(DerivationInfo( + derivationType: DerivationType.bip39, + balance: nanoUtil!.getRawAsUsableString(bip39Info.balance, nanoUtil!.rawPerNano), + address: bip39Info.address!, + transactionsCount: bip39Info.confirmationHeight, + )); + } + return list; + } } diff --git a/lib/src/screens/restore/wallet_restore_choose_derivation.dart b/lib/src/screens/restore/wallet_restore_choose_derivation.dart index 5cf40e588..9a7d8eb67 100644 --- a/lib/src/screens/restore/wallet_restore_choose_derivation.dart +++ b/lib/src/screens/restore/wallet_restore_choose_derivation.dart @@ -1,8 +1,5 @@ -import 'package:cake_wallet/di.dart'; import 'package:cake_wallet/generated/i18n.dart'; -import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; -import 'package:cake_wallet/themes/theme_base.dart'; import 'package:cake_wallet/view_model/wallet_restore_choose_derivation_view_model.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:flutter/material.dart'; @@ -13,15 +10,14 @@ class WalletRestoreChooseDerivationPage extends BasePage { WalletRestoreChooseDerivationPage(this.walletRestoreChooseDerivationViewModel) {} @override - Widget middle(BuildContext context) => Observer( - builder: (_) => Text( - S.current.choose_derivation, - style: TextStyle( - fontSize: 18.0, - fontWeight: FontWeight.bold, - fontFamily: 'Lato', - color: titleColor(context)), - )); + Widget middle(BuildContext context) => Text( + S.current.choose_derivation, + style: TextStyle( + fontSize: 18.0, + fontWeight: FontWeight.bold, + fontFamily: 'Lato', + color: titleColor(context)), + ); final WalletRestoreChooseDerivationViewModel walletRestoreChooseDerivationViewModel; DerivationType derivationType = DerivationType.unknown; @@ -105,7 +101,7 @@ class WalletRestoreChooseDerivationPage extends BasePage { ), ), Text( - "${S.current.transactions}: ${derivation.height}", + "${S.current.transactions}: ${derivation.transactionsCount}", style: Theme.of(context).primaryTextTheme.labelMedium!.copyWith( fontSize: 16, fontWeight: FontWeight.w500, diff --git a/lib/src/screens/restore/wallet_restore_from_seed_form.dart b/lib/src/screens/restore/wallet_restore_from_seed_form.dart index 6f8f9eb2b..288862ce7 100644 --- a/lib/src/screens/restore/wallet_restore_from_seed_form.dart +++ b/lib/src/screens/restore/wallet_restore_from_seed_form.dart @@ -20,6 +20,7 @@ class WalletRestoreFromSeedForm extends StatefulWidget { {Key? key, required this.displayLanguageSelector, required this.displayBlockHeightSelector, + required this.displayPassphrase, required this.type, required this.seedTypeViewModel, this.blockHeightFocusNode, @@ -31,6 +32,7 @@ class WalletRestoreFromSeedForm extends StatefulWidget { final WalletType type; final bool displayLanguageSelector; final bool displayBlockHeightSelector; + final bool displayPassphrase; final SeedTypeViewModel seedTypeViewModel; final FocusNode? blockHeightFocusNode; final Function(bool)? onHeightOrDateEntered; @@ -48,6 +50,7 @@ class WalletRestoreFromSeedFormState extends State { formKey = GlobalKey(), languageController = TextEditingController(), nameTextEditingController = TextEditingController(), + passphraseController = TextEditingController(), seedTypeController = TextEditingController(); final GlobalKey seedWidgetStateKey; @@ -55,6 +58,7 @@ class WalletRestoreFromSeedFormState extends State { final TextEditingController languageController; final TextEditingController nameTextEditingController; final TextEditingController seedTypeController; + final TextEditingController passphraseController; final GlobalKey formKey; late ReactionDisposer moneroSeedTypeReaction; String language; @@ -166,15 +170,15 @@ class WalletRestoreFromSeedFormState extends State { ), if (widget.displayLanguageSelector) GestureDetector( - onTap: () async { - await showPopUp( - context: context, - builder: (_) => SeedLanguagePicker( - selected: language, - onItemSelected: _changeLanguage, - seedType: isPolyseed ? SeedType.polyseed : SeedType.legacy, - )); - }, + onTap: () async { + await showPopUp( + context: context, + builder: (_) => SeedLanguagePicker( + selected: language, + onItemSelected: _changeLanguage, + seedType: isPolyseed ? SeedType.polyseed : SeedType.legacy, + )); + }, child: Container( color: Colors.transparent, padding: EdgeInsets.only(top: 20.0), @@ -194,6 +198,14 @@ class WalletRestoreFromSeedFormState extends State { key: blockchainHeightKey, onHeightOrDateEntered: widget.onHeightOrDateEntered, hasDatePicker: widget.type == WalletType.monero), + if (widget.displayPassphrase) ...[ + const SizedBox(height: 10), + BaseTextFormField( + hintText: S.current.passphrase, + controller: passphraseController, + obscureText: true, + ), + ] ])); } diff --git a/lib/src/screens/restore/wallet_restore_page.dart b/lib/src/screens/restore/wallet_restore_page.dart index fe5ac8487..6fcacfb0a 100644 --- a/lib/src/screens/restore/wallet_restore_page.dart +++ b/lib/src/screens/restore/wallet_restore_page.dart @@ -1,7 +1,5 @@ import 'package:cake_wallet/core/execution_state.dart'; -import 'package:cake_wallet/di.dart'; import 'package:cake_wallet/generated/i18n.dart'; -import 'package:cake_wallet/nano/nano.dart'; import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/screens/restore/wallet_restore_from_keys_form.dart'; @@ -9,7 +7,6 @@ import 'package:cake_wallet/src/screens/restore/wallet_restore_from_seed_form.da import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; import 'package:cake_wallet/src/widgets/keyboard_done_button.dart'; import 'package:cake_wallet/src/widgets/primary_button.dart'; -import 'package:cake_wallet/store/app_store.dart'; import 'package:cake_wallet/themes/extensions/keyboard_theme.dart'; import 'package:cake_wallet/themes/extensions/wallet_list_theme.dart'; import 'package:cake_wallet/utils/responsive_layout_util.dart'; @@ -17,7 +14,6 @@ import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cake_wallet/view_model/restore/restore_mode.dart'; import 'package:cake_wallet/view_model/seed_type_view_model.dart'; import 'package:cake_wallet/view_model/wallet_restore_view_model.dart'; -import 'package:cw_core/nano_account_info_response.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:flutter/material.dart'; @@ -42,6 +38,7 @@ class WalletRestorePage extends BasePage { displayBlockHeightSelector: walletRestoreViewModel.hasBlockchainHeightLanguageSelector, displayLanguageSelector: walletRestoreViewModel.hasSeedLanguageSelector, + displayPassphrase: walletRestoreViewModel.hasPassphrase, type: walletRestoreViewModel.type, key: walletRestoreFromSeedFormKey, blockHeightFocusNode: _blockHeightFocusNode, @@ -99,8 +96,10 @@ class WalletRestorePage extends BasePage { final GlobalKey walletRestoreFromSeedFormKey; final GlobalKey walletRestoreFromKeysFormKey; final FocusNode _blockHeightFocusNode; - DerivationType derivationType = DerivationType.unknown; - String? derivationPath = null; + + // DerivationType derivationType = DerivationType.unknown; + // String? derivationPath = null; + DerivationInfo? derivationInfo; @override Widget body(BuildContext context) { @@ -298,6 +297,11 @@ class WalletRestorePage extends BasePage { -1; } + if (walletRestoreViewModel.hasPassphrase) { + credentials['passphrase'] = + walletRestoreFromSeedFormKey.currentState!.passphraseController.text; + } + credentials['name'] = walletRestoreFromSeedFormKey.currentState!.nameTextEditingController.text; } else if (walletRestoreViewModel.mode == WalletRestoreMode.keys) { @@ -318,58 +322,11 @@ class WalletRestorePage extends BasePage { } } - credentials['derivationType'] = this.derivationType; - credentials['derivationPath'] = this.derivationPath; + credentials['derivationInfo'] = this.derivationInfo; credentials['walletType'] = walletRestoreViewModel.type; return credentials; } - Future> getDerivationInfo(dynamic credentials) async { - var list = []; - var walletType = credentials["walletType"] as WalletType; - var appStore = getIt.get(); - var node = appStore.settingsStore.getCurrentNode(walletType); - - switch (walletType) { - case WalletType.nano: - String? mnemonic = credentials['seed'] as String?; - String? seedKey = credentials['private_key'] as String?; - AccountInfoResponse? bip39Info = await nanoUtil!.getInfoFromSeedOrMnemonic( - DerivationType.bip39, - mnemonic: mnemonic, - seedKey: seedKey, - node: node); - AccountInfoResponse? standardInfo = await nanoUtil!.getInfoFromSeedOrMnemonic( - DerivationType.nano, - mnemonic: mnemonic, - seedKey: seedKey, - node: node, - ); - - if (standardInfo?.balance != null) { - list.add(DerivationInfo( - derivationType: DerivationType.nano, - balance: nanoUtil!.getRawAsUsableString(standardInfo!.balance, nanoUtil!.rawPerNano), - address: standardInfo.address!, - height: standardInfo.confirmationHeight, - )); - } - - if (bip39Info?.balance != null) { - list.add(DerivationInfo( - derivationType: DerivationType.bip39, - balance: nanoUtil!.getRawAsUsableString(bip39Info!.balance, nanoUtil!.rawPerNano), - address: bip39Info.address!, - height: bip39Info.confirmationHeight, - )); - } - break; - default: - break; - } - return list; - } - Future _confirmForm(BuildContext context) async { // Dismissing all visible keyboard to provide context for navigation FocusManager.instance.primaryFocus?.unfocus(); @@ -398,51 +355,46 @@ class WalletRestorePage extends BasePage { walletRestoreViewModel.state = IsExecutingState(); - List derivationTypes = - await walletRestoreViewModel.getDerivationTypes(_credentials()); + DerivationInfo? dInfo; - if (derivationTypes[0] == DerivationType.unknown || derivationTypes.length > 1) { - // push screen to choose the derivation type: - List derivations = await getDerivationInfo(_credentials()); + // get info about the different derivations: + List derivations = + await walletRestoreViewModel.getDerivationInfo(_credentials()); - int derivationsWithHistory = 0; - int derivationWithHistoryIndex = 0; - for (int i = 0; i < derivations.length; i++) { - if (derivations[i].height > 0) { - derivationsWithHistory++; - derivationWithHistoryIndex = i; - } + int derivationsWithHistory = 0; + int derivationWithHistoryIndex = 0; + for (int i = 0; i < derivations.length; i++) { + if (derivations[i].transactionsCount > 0) { + derivationsWithHistory++; + derivationWithHistoryIndex = i; } - - DerivationInfo? derivationInfo; - - if (derivationsWithHistory > 1) { - derivationInfo = await Navigator.of(context).pushNamed(Routes.restoreWalletChooseDerivation, - arguments: derivations) as DerivationInfo?; - } else if (derivationsWithHistory == 1) { - derivationInfo = derivations[derivationWithHistoryIndex]; - } else if (derivationsWithHistory == 0) { - // default derivation: - derivationInfo = DerivationInfo( - derivationType: derivationTypes[0], - derivationPath: "m/0'/1", - height: 0, - ); - } - - if (derivationInfo == null) { - walletRestoreViewModel.state = InitialExecutionState(); - return; - } - this.derivationType = derivationInfo.derivationType; - this.derivationPath = derivationInfo.derivationPath; - } else { - // electrum derivation: - this.derivationType = derivationTypes[0]; - this.derivationPath = "m/0'/1"; } - walletRestoreViewModel.state = InitialExecutionState(); + if (derivationsWithHistory > 1) { + dInfo = await Navigator.of(context).pushNamed( + Routes.restoreWalletChooseDerivation, + arguments: derivations, + ) as DerivationInfo?; + } else if (derivationsWithHistory == 1) { + dInfo = derivations[derivationWithHistoryIndex]; + } + + // get the default derivation for this wallet type: + if (dInfo == null) { + // we only return 1 derivation if we're pretty sure we know which one to use: + if (derivations.length == 1) { + dInfo = derivations.first; + } else { + // if we have multiple possible derivations, and none have histories + // we just default to the most common one: + dInfo = walletRestoreViewModel.getCommonRestoreDerivation(); + } + } + + this.derivationInfo = dInfo; + if (this.derivationInfo == null) { + this.derivationInfo = walletRestoreViewModel.getDefaultDerivation(); + } walletRestoreViewModel.create(options: _credentials()); } diff --git a/lib/src/screens/wallet_list/wallet_list_page.dart b/lib/src/screens/wallet_list/wallet_list_page.dart index b57473cba..81c78b1ab 100644 --- a/lib/src/screens/wallet_list/wallet_list_page.dart +++ b/lib/src/screens/wallet_list/wallet_list_page.dart @@ -343,7 +343,9 @@ class WalletListBodyState extends State { }); } } catch (e) { - changeProcessText(S.of(context).wallet_list_failed_to_load(wallet.name, e.toString())); + if (this.mounted) { + changeProcessText(S.of(context).wallet_list_failed_to_load(wallet.name, e.toString())); + } } }, conditionToDetermineIfToUse2FA: diff --git a/lib/src/widgets/base_text_form_field.dart b/lib/src/widgets/base_text_form_field.dart index 5649a0784..534e6dae2 100644 --- a/lib/src/widgets/base_text_form_field.dart +++ b/lib/src/widgets/base_text_form_field.dart @@ -22,6 +22,7 @@ class BaseTextFormField extends StatelessWidget { this.enabled = true, this.readOnly = false, this.enableInteractiveSelection = true, + this.obscureText = false, this.validator, this.textStyle, this.placeholderTextStyle, @@ -57,6 +58,7 @@ class BaseTextFormField extends StatelessWidget { final String? initialValue; final double borderWidth; final void Function(String)? onSubmit; + final bool obscureText; @override Widget build(BuildContext context) { @@ -70,6 +72,7 @@ class BaseTextFormField extends StatelessWidget { textInputAction: textInputAction, textAlign: textAlign, autovalidateMode: autovalidateMode, + obscureText: obscureText, maxLines: maxLines, inputFormatters: inputFormatters, enabled: enabled, diff --git a/lib/view_model/restore/restore_from_qr_vm.dart b/lib/view_model/restore/restore_from_qr_vm.dart index 31f0bfdd2..b9b493f04 100644 --- a/lib/view_model/restore/restore_from_qr_vm.dart +++ b/lib/view_model/restore/restore_from_qr_vm.dart @@ -30,8 +30,7 @@ abstract class WalletRestorationFromQRVMBase extends WalletCreationVM with Store spendKey = '', wif = '', address = '', - super(appStore, walletInfoSource, walletCreationService, - type: type, isRecovery: true); + super(appStore, walletInfoSource, walletCreationService, type: type, isRecovery: true); @observable int height; @@ -51,8 +50,16 @@ abstract class WalletRestorationFromQRVMBase extends WalletCreationVM with Store bool get hasRestorationHeight => type == WalletType.monero; @override - WalletCredentials getCredentialsFromRestoredWallet(dynamic options, RestoredWallet restoreWallet) { + WalletCredentials getCredentialsFromRestoredWallet( + dynamic options, RestoredWallet restoreWallet) { final password = generateWalletPassword(); + String? passphrase; + DerivationInfo? derivationInfo; + if (options != null) { + derivationInfo = options["derivationInfo"] as DerivationInfo?; + passphrase = options["passphrase"] as String?; + } + derivationInfo ??= getDefaultDerivation(); switch (restoreWallet.restoreMode) { case WalletRestoreMode.keys: @@ -86,23 +93,37 @@ abstract class WalletRestorationFromQRVMBase extends WalletCreationVM with Store switch (restoreWallet.type) { case WalletType.monero: return monero!.createMoneroRestoreWalletFromSeedCredentials( - name: name, - height: restoreWallet.height ?? 0, - mnemonic: restoreWallet.mnemonicSeed ?? '', - password: password); + name: name, + height: restoreWallet.height ?? 0, + mnemonic: restoreWallet.mnemonicSeed ?? '', + password: password, + ); case WalletType.bitcoin: case WalletType.litecoin: return bitcoin!.createBitcoinRestoreWalletFromSeedCredentials( - name: name, mnemonic: restoreWallet.mnemonicSeed ?? '', password: password); + name: name, + mnemonic: restoreWallet.mnemonicSeed ?? '', + password: password, + passphrase: passphrase, + derivationType: derivationInfo!.derivationType!, + derivationPath: derivationInfo.derivationPath!, + ); case WalletType.bitcoinCash: return bitcoinCash!.createBitcoinCashRestoreWalletFromSeedCredentials( - name: name, mnemonic: restoreWallet.mnemonicSeed ?? '', password: password); + name: name, + mnemonic: restoreWallet.mnemonicSeed ?? '', + password: password, + ); case WalletType.ethereum: return ethereum!.createEthereumRestoreWalletFromSeedCredentials( name: name, mnemonic: restoreWallet.mnemonicSeed ?? '', password: password); case WalletType.nano: return nano!.createNanoRestoreWalletFromSeedCredentials( - name: name, mnemonic: restoreWallet.mnemonicSeed ?? '', password: password); + name: name, + mnemonic: restoreWallet.mnemonicSeed ?? '', + password: password, + derivationType: derivationInfo!.derivationType!, + ); case WalletType.polygon: return polygon!.createPolygonRestoreWalletFromSeedCredentials( name: name, mnemonic: restoreWallet.mnemonicSeed ?? '', password: password); @@ -118,7 +139,8 @@ abstract class WalletRestorationFromQRVMBase extends WalletCreationVM with Store } @override - Future processFromRestoredWallet(WalletCredentials credentials, RestoredWallet restoreWallet) async { + Future processFromRestoredWallet( + WalletCredentials credentials, RestoredWallet restoreWallet) async { try { switch (restoreWallet.restoreMode) { case WalletRestoreMode.keys: diff --git a/lib/view_model/send/send_view_model.dart b/lib/view_model/send/send_view_model.dart index cabb723e1..6c0c3870b 100644 --- a/lib/view_model/send/send_view_model.dart +++ b/lib/view_model/send/send_view_model.dart @@ -423,7 +423,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor Object _credentials() { final priority = _settingsStore.priority[wallet.type]; - if (priority == null && wallet.type != WalletType.nano && wallet.type != WalletType.solana) { + if (priority == null && wallet.type != WalletType.nano && wallet.type != WalletType.banano && wallet.type != WalletType.solana) { throw Exception('Priority is null for wallet type: ${wallet.type}'); } diff --git a/lib/view_model/wallet_creation_vm.dart b/lib/view_model/wallet_creation_vm.dart index 4a1e054d6..5c9c29a16 100644 --- a/lib/view_model/wallet_creation_vm.dart +++ b/lib/view_model/wallet_creation_vm.dart @@ -71,9 +71,9 @@ abstract class WalletCreationVMBase with Store { dirPath: dirPath, address: '', showIntroCakePayCard: (!walletCreationService.typeExists(type)) && type != WalletType.haven, - derivationPath: credentials.derivationPath, - derivationType: credentials.derivationType, + derivationInfo: credentials.derivationInfo ?? getDefaultDerivation(), ); + credentials.walletInfo = walletInfo; final wallet = restoreWallet != null ? await processFromRestoredWallet(credentials, restoreWallet) @@ -89,6 +89,48 @@ abstract class WalletCreationVMBase with Store { } } + DerivationInfo? getDefaultDerivation() { + switch (this.type) { + case WalletType.nano: + return DerivationInfo( + derivationType: DerivationType.nano, + ); + case WalletType.bitcoin: + case WalletType.litecoin: + return DerivationInfo( + derivationType: DerivationType.electrum, + derivationPath: "m/0'/0", + ); + default: + return null; + } + } + + DerivationInfo? getCommonRestoreDerivation() { + switch (this.type) { + case WalletType.nano: + return DerivationInfo( + derivationType: DerivationType.nano, + ); + case WalletType.bitcoin: + return DerivationInfo( + derivationType: DerivationType.bip39, + derivationPath: "m/84'/0'/0'/0", + description: "Standard BIP84 native segwit", + scriptType: "p2wpkh", + ); + case WalletType.litecoin: + return DerivationInfo( + derivationType: DerivationType.bip39, + derivationPath: "m/84'/2'/0'/0", + description: "Standard BIP84 native segwit (litecoin)", + scriptType: "p2wpkh", + ); + default: + return null; + } + } + WalletCredentials getCredentials(dynamic options) => throw UnimplementedError(); Future process(WalletCredentials credentials) => throw UnimplementedError(); diff --git a/lib/view_model/wallet_restore_view_model.dart b/lib/view_model/wallet_restore_view_model.dart index 93ca813d6..21339f1ae 100644 --- a/lib/view_model/wallet_restore_view_model.dart +++ b/lib/view_model/wallet_restore_view_model.dart @@ -2,6 +2,7 @@ import 'package:cake_wallet/bitcoin/bitcoin.dart'; import 'package:cake_wallet/di.dart'; import 'package:cake_wallet/nano/nano.dart'; import 'package:cake_wallet/ethereum/ethereum.dart'; +import 'package:cw_core/nano_account_info_response.dart'; import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart'; import 'package:cake_wallet/polygon/polygon.dart'; import 'package:cake_wallet/solana/solana.dart'; @@ -66,6 +67,8 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store { final bool hasBlockchainHeightLanguageSelector; final bool hasRestoreFromPrivateKey; + bool get hasPassphrase => [WalletType.bitcoin, WalletType.litecoin].contains(type); + @observable WalletRestoreMode mode; @@ -75,10 +78,10 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store { @override WalletCredentials getCredentials(dynamic options) { final password = generateWalletPassword(); + String? passphrase = options['passphrase'] as String?; final height = options['height'] as int? ?? 0; name = options['name'] as String; - DerivationType? derivationType = options["derivationType"] as DerivationType?; - String? derivationPath = options["derivationPath"] as String?; + DerivationInfo? derivationInfo = options["derivationInfo"] as DerivationInfo?; if (mode == WalletRestoreMode.seed) { final seed = options['seed'] as String; @@ -87,14 +90,15 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store { return monero!.createMoneroRestoreWalletFromSeedCredentials( name: name, height: height, mnemonic: seed, password: password); case WalletType.bitcoin: + case WalletType.litecoin: return bitcoin!.createBitcoinRestoreWalletFromSeedCredentials( name: name, mnemonic: seed, password: password, + passphrase: passphrase, + derivationType: derivationInfo!.derivationType!, + derivationPath: derivationInfo.derivationPath!, ); - case WalletType.litecoin: - return bitcoin!.createBitcoinRestoreWalletFromSeedCredentials( - name: name, mnemonic: seed, password: password); case WalletType.haven: return haven!.createHavenRestoreWalletFromSeedCredentials( name: name, height: height, mnemonic: seed, password: password); @@ -106,7 +110,11 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store { name: name, mnemonic: seed, password: password); case WalletType.nano: return nano!.createNanoRestoreWalletFromSeedCredentials( - name: name, mnemonic: seed, password: password, derivationType: derivationType); + name: name, + mnemonic: seed, + password: password, + derivationType: derivationInfo!.derivationType!, + ); case WalletType.polygon: return polygon!.createPolygonRestoreWalletFromSeedCredentials( name: name, @@ -185,23 +193,34 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store { throw Exception('Unexpected type: ${type.toString()}'); } - Future> getDerivationTypes(dynamic options) async { - final seedKey = options['private_key'] as String?; - final mnemonic = options['seed'] as String?; - WalletType walletType = options['walletType'] as WalletType; + Future> getDerivationInfo(dynamic credentials) async { + var list = []; + var walletType = credentials["walletType"] as WalletType; var appStore = getIt.get(); var node = appStore.settingsStore.getCurrentNode(walletType); - switch (type) { + switch (walletType) { + case WalletType.bitcoin: + case WalletType.litecoin: + String? mnemonic = credentials['seed'] as String?; + String? passphrase = credentials['passphrase'] as String?; + return bitcoin!.getDerivationsFromMnemonic( + mnemonic: mnemonic!, + node: node, + passphrase: passphrase, + ); case WalletType.nano: - return nanoUtil! - .compareDerivationMethods(mnemonic: mnemonic, privateKey: seedKey, node: node); + String? mnemonic = credentials['seed'] as String?; + String? seedKey = credentials['private_key'] as String?; + return nanoUtil!.getDerivationsFromMnemonic( + mnemonic: mnemonic, + seedKey: seedKey, + node: node, + ); default: break; } - - // throw Exception('Unexpected type: ${type.toString()}'); - return [DerivationType.def]; + return list; } @override @@ -209,7 +228,6 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store { if (mode == WalletRestoreMode.keys) { return walletCreationService.restoreFromKeys(credentials, isTestnet: useTestnet); } - return walletCreationService.restoreFromSeed(credentials, isTestnet: useTestnet); } } diff --git a/res/values/strings_ar.arb b/res/values/strings_ar.arb index cf9959f17..16a87a850 100644 --- a/res/values/strings_ar.arb +++ b/res/values/strings_ar.arb @@ -411,6 +411,7 @@ "outputs": "المخرجات", "overwrite_amount": "تغير المبلغ", "pairingInvalidEvent": "ﺢﻟﺎﺻ ﺮﻴﻏ ﺙﺪﺣ ﻥﺍﺮﻗﺇ", + "passphrase": "عبارة الممر (اختياري)", "password": "كلمة المرور", "paste": "لصق", "pause_wallet_creation": ".ﺎﻴًﻟﺎﺣ ﺎﺘًﻗﺆﻣ ﺔﻔﻗﻮﺘﻣ Haven Wallet ءﺎﺸﻧﺇ ﻰﻠﻋ ﺓﺭﺪﻘﻟﺍ", diff --git a/res/values/strings_bg.arb b/res/values/strings_bg.arb index bd1cd645d..4e92cd707 100644 --- a/res/values/strings_bg.arb +++ b/res/values/strings_bg.arb @@ -411,6 +411,7 @@ "outputs": "Изходи", "overwrite_amount": "Промени сума", "pairingInvalidEvent": "Невалидно събитие при сдвояване", + "passphrase": "Passphrase (по избор)", "password": "Парола", "paste": "Поставяне", "pause_wallet_creation": "Възможността за създаване на Haven Wallet в момента е на пауза.", diff --git a/res/values/strings_cs.arb b/res/values/strings_cs.arb index 4d3458bec..95fdc2a93 100644 --- a/res/values/strings_cs.arb +++ b/res/values/strings_cs.arb @@ -411,6 +411,7 @@ "outputs": "Výstupy", "overwrite_amount": "Přepsat částku", "pairingInvalidEvent": "Neplatná událost párování", + "passphrase": "Passphrase (volitelné)", "password": "Heslo", "paste": "Vložit", "pause_wallet_creation": "Možnost vytvářet Haven Wallet je momentálně pozastavena.", diff --git a/res/values/strings_de.arb b/res/values/strings_de.arb index 0546140eb..d2731d3e7 100644 --- a/res/values/strings_de.arb +++ b/res/values/strings_de.arb @@ -411,6 +411,7 @@ "outputs": "Ausgänge", "overwrite_amount": "Overwrite amount", "pairingInvalidEvent": "Paarung ungültiges Ereignis", + "passphrase": "Passphrase (optional)", "password": "Passwort", "paste": "Einfügen", "pause_wallet_creation": "Die Möglichkeit, Haven Wallet zu erstellen, ist derzeit pausiert.", @@ -425,8 +426,8 @@ "placeholder_transactions": "Ihre Transaktionen werden hier angezeigt", "please_fill_totp": "Bitte geben Sie den 8-stelligen Code ein, der auf Ihrem anderen Gerät vorhanden ist", "please_make_selection": "Bitte treffen Sie unten eine Auswahl zum Erstellen oder Wiederherstellen Ihrer Wallet.", - "Please_reference_document": "Weitere Informationen finden Sie in den Dokumenten unten.", "please_reference_document": "Bitte verweisen Sie auf die folgenden Dokumente, um weitere Informationen zu erhalten.", + "Please_reference_document": "Weitere Informationen finden Sie in den Dokumenten unten.", "please_select": "Bitte auswählen:", "please_select_backup_file": "Bitte wählen Sie die Sicherungsdatei und geben Sie das Sicherungskennwort ein.", "please_try_to_connect_to_another_node": "Bitte versuchen Sie, sich mit einem anderen Knoten zu verbinden", @@ -822,4 +823,4 @@ "you_will_get": "Konvertieren zu", "you_will_send": "Konvertieren von", "yy": "YY" -} +} \ No newline at end of file diff --git a/res/values/strings_en.arb b/res/values/strings_en.arb index 8f8b753d6..8c302d096 100644 --- a/res/values/strings_en.arb +++ b/res/values/strings_en.arb @@ -411,6 +411,7 @@ "outputs": "Outputs", "overwrite_amount": "Overwrite amount", "pairingInvalidEvent": "Pairing Invalid Event", + "passphrase": "Passphrase (Optional)", "password": "Password", "paste": "Paste", "pause_wallet_creation": "Ability to create Haven Wallet is currently paused.", diff --git a/res/values/strings_es.arb b/res/values/strings_es.arb index 7de9cff53..17c4ff681 100644 --- a/res/values/strings_es.arb +++ b/res/values/strings_es.arb @@ -411,6 +411,7 @@ "outputs": "Salidas", "overwrite_amount": "Overwrite amount", "pairingInvalidEvent": "Evento de emparejamiento no válido", + "passphrase": "Passfrase (opcional)", "password": "Contraseña", "paste": "Pegar", "pause_wallet_creation": "La capacidad para crear Haven Wallet está actualmente pausada.", diff --git a/res/values/strings_fr.arb b/res/values/strings_fr.arb index 2c76122fc..12716ab33 100644 --- a/res/values/strings_fr.arb +++ b/res/values/strings_fr.arb @@ -411,6 +411,7 @@ "outputs": "Les sorties", "overwrite_amount": "Remplacer le montant", "pairingInvalidEvent": "Événement de couplage non valide", + "passphrase": "Phrase de passe (facultative)", "password": "Mot de passe", "paste": "Coller", "pause_wallet_creation": "La possibilité de créer Haven Wallet est actuellement suspendue.", diff --git a/res/values/strings_ha.arb b/res/values/strings_ha.arb index bac970207..29754cf72 100644 --- a/res/values/strings_ha.arb +++ b/res/values/strings_ha.arb @@ -413,6 +413,7 @@ "outputs": "Abubuwan fashewa", "overwrite_amount": "Rubuta adadin", "pairingInvalidEvent": "Haɗa Lamarin mara inganci", + "passphrase": "Passphrase (Zabi)", "password": "Kalmar wucewa", "paste": "Manna", "pause_wallet_creation": "A halin yanzu an dakatar da ikon ƙirƙirar Haven Wallet.", diff --git a/res/values/strings_hi.arb b/res/values/strings_hi.arb index 5a9706bd5..278adde0f 100644 --- a/res/values/strings_hi.arb +++ b/res/values/strings_hi.arb @@ -411,6 +411,7 @@ "outputs": "आउटपुट", "overwrite_amount": "Overwrite amount", "pairingInvalidEvent": "अमान्य ईवेंट युग्मित करना", + "passphrase": "पासफ्रेज़ (वैकल्पिक)", "password": "पारण शब्द", "paste": "पेस्ट करें", "pause_wallet_creation": "हेवन वॉलेट बनाने की क्षमता फिलहाल रुकी हुई है।", diff --git a/res/values/strings_hr.arb b/res/values/strings_hr.arb index 94f675a1d..7940b1add 100644 --- a/res/values/strings_hr.arb +++ b/res/values/strings_hr.arb @@ -411,6 +411,7 @@ "outputs": "Izlazi", "overwrite_amount": "Overwrite amount", "pairingInvalidEvent": "Nevažeći događaj uparivanja", + "passphrase": "Prolaznica (neobavezno)", "password": "Lozinka", "paste": "Zalijepi", "pause_wallet_creation": "Mogućnost stvaranja novčanika Haven trenutno je pauzirana.", diff --git a/res/values/strings_id.arb b/res/values/strings_id.arb index 69e270d10..8177afdc2 100644 --- a/res/values/strings_id.arb +++ b/res/values/strings_id.arb @@ -413,6 +413,7 @@ "outputs": "Output", "overwrite_amount": "Timpa jumlah", "pairingInvalidEvent": "Menyandingkan Acara Tidak Valid", + "passphrase": "Frasa sandi (opsional)", "password": "Kata Sandi", "paste": "Tempel", "pause_wallet_creation": "Kemampuan untuk membuat Haven Wallet saat ini dijeda.", diff --git a/res/values/strings_it.arb b/res/values/strings_it.arb index 09b3e43bb..4cc08f9b1 100644 --- a/res/values/strings_it.arb +++ b/res/values/strings_it.arb @@ -413,6 +413,7 @@ "outputs": "Output", "overwrite_amount": "Sovrascrivi quantità", "pairingInvalidEvent": "Associazione evento non valido", + "passphrase": "Passphrase (opzionale)", "password": "Password", "paste": "Incolla", "pause_wallet_creation": "La possibilità di creare Haven Wallet è attualmente sospesa.", diff --git a/res/values/strings_ja.arb b/res/values/strings_ja.arb index b067c2721..a72bbb0e4 100644 --- a/res/values/strings_ja.arb +++ b/res/values/strings_ja.arb @@ -412,6 +412,7 @@ "outputs": "出力", "overwrite_amount": "Overwrite amount", "pairingInvalidEvent": "ペアリング無効イベント", + "passphrase": "パスフレーズ(オプション)", "password": "パスワード", "paste": "ペースト", "pause_wallet_creation": "Haven Wallet を作成する機能は現在一時停止されています。", diff --git a/res/values/strings_ko.arb b/res/values/strings_ko.arb index d9881ad04..b80494e80 100644 --- a/res/values/strings_ko.arb +++ b/res/values/strings_ko.arb @@ -411,6 +411,7 @@ "outputs": "출력", "overwrite_amount": "Overwrite amount", "pairingInvalidEvent": "잘못된 이벤트 페어링", + "passphrase": "암호화 (선택 사항)", "password": "암호", "paste": "풀", "pause_wallet_creation": "Haven Wallet 생성 기능이 현재 일시 중지되었습니다.", @@ -425,8 +426,8 @@ "placeholder_transactions": "거래가 여기에 표시됩니다", "please_fill_totp": "다른 기기에 있는 8자리 코드를 입력하세요.", "please_make_selection": "아래에서 선택하십시오 지갑 만들기 또는 복구.", - "please_reference_document": "자세한 내용은 아래 문서를 참조하십시오.", "Please_reference_document": "자세한 내용은 아래 문서를 참조하십시오.", + "please_reference_document": "자세한 내용은 아래 문서를 참조하십시오.", "please_select": "선택 해주세요:", "please_select_backup_file": "백업 파일을 선택하고 백업 암호를 입력하십시오.", "please_try_to_connect_to_another_node": "다른 노드에 연결을 시도하십시오", diff --git a/res/values/strings_my.arb b/res/values/strings_my.arb index c36f63414..97a22d807 100644 --- a/res/values/strings_my.arb +++ b/res/values/strings_my.arb @@ -411,6 +411,7 @@ "outputs": "ထုတ်လုပ်မှု", "overwrite_amount": "ပမာဏကို ထပ်ရေးပါ။", "pairingInvalidEvent": "မမှန်ကန်သောဖြစ်ရပ်ကို တွဲချိတ်ခြင်း။", + "passphrase": "passphrase (optional)", "password": "စကားဝှက်", "paste": "ငါးပိ", "pause_wallet_creation": "Haven Wallet ဖန်တီးနိုင်မှုကို လောလောဆယ် ခေတ္တရပ်ထားသည်။", diff --git a/res/values/strings_nl.arb b/res/values/strings_nl.arb index f258b8f62..a64e264c0 100644 --- a/res/values/strings_nl.arb +++ b/res/values/strings_nl.arb @@ -411,6 +411,7 @@ "outputs": "Uitgangen", "overwrite_amount": "Overwrite amount", "pairingInvalidEvent": "Koppelen Ongeldige gebeurtenis", + "passphrase": "PassaspHRASE (optioneel)", "password": "Wachtwoord", "paste": "Plakken", "pause_wallet_creation": "De mogelijkheid om Haven Wallet te maken is momenteel onderbroken.", diff --git a/res/values/strings_pl.arb b/res/values/strings_pl.arb index 4627d0242..109a800ad 100644 --- a/res/values/strings_pl.arb +++ b/res/values/strings_pl.arb @@ -411,6 +411,7 @@ "outputs": "Wyjścia", "overwrite_amount": "Nadpisz ilość", "pairingInvalidEvent": "Nieprawidłowe zdarzenie parowania", + "passphrase": "PassPhraza (opcjonalnie)", "password": "Hasło", "paste": "Wklej", "pause_wallet_creation": "Możliwość utworzenia Portfela Haven jest obecnie wstrzymana.", diff --git a/res/values/strings_pt.arb b/res/values/strings_pt.arb index 2a781c76b..2d877794a 100644 --- a/res/values/strings_pt.arb +++ b/res/values/strings_pt.arb @@ -413,6 +413,7 @@ "outputs": "Saídas", "overwrite_amount": "Overwrite amount", "pairingInvalidEvent": "Emparelhamento de evento inválido", + "passphrase": "Senha (opcional)", "password": "Senha", "paste": "Colar", "pause_wallet_creation": "A capacidade de criar a Haven Wallet está atualmente pausada.", diff --git a/res/values/strings_ru.arb b/res/values/strings_ru.arb index 22bac3e33..e6141c29b 100644 --- a/res/values/strings_ru.arb +++ b/res/values/strings_ru.arb @@ -412,6 +412,7 @@ "outputs": "Выходы", "overwrite_amount": "Overwrite amount", "pairingInvalidEvent": "Недействительное событие сопряжения", + "passphrase": "Passfrase (необязательно)", "password": "Пароль", "paste": "Вставить", "pause_wallet_creation": "Возможность создания Haven Wallet в настоящее время приостановлена.", diff --git a/res/values/strings_th.arb b/res/values/strings_th.arb index c0f58495c..ef1a3ea4e 100644 --- a/res/values/strings_th.arb +++ b/res/values/strings_th.arb @@ -411,6 +411,7 @@ "outputs": "เอาต์พุต", "overwrite_amount": "เขียนทับจำนวน", "pairingInvalidEvent": "การจับคู่เหตุการณ์ที่ไม่ถูกต้อง", + "passphrase": "ข้อความรหัสผ่าน (ไม่บังคับ)", "password": "รหัสผ่าน", "paste": "วาง", "pause_wallet_creation": "ขณะนี้ความสามารถในการสร้าง Haven Wallet ถูกหยุดชั่วคราว", diff --git a/res/values/strings_tl.arb b/res/values/strings_tl.arb index 8c3b13b3b..e0258e38a 100644 --- a/res/values/strings_tl.arb +++ b/res/values/strings_tl.arb @@ -411,6 +411,7 @@ "outputs": "Mga output", "overwrite_amount": "Overwrite na halaga", "pairingInvalidEvent": "Pagpares ng Di-wastong Kaganapan", + "passphrase": "Passphrase (opsyonal)", "password": "Password", "paste": "I -paste", "pause_wallet_creation": "Kasalukuyang naka-pause ang kakayahang gumawa ng Haven Wallet.", diff --git a/res/values/strings_tr.arb b/res/values/strings_tr.arb index 534a36c77..6cacbfd42 100644 --- a/res/values/strings_tr.arb +++ b/res/values/strings_tr.arb @@ -411,6 +411,7 @@ "outputs": "çıktılar", "overwrite_amount": "Miktarın üzerine yaz", "pairingInvalidEvent": "Geçersiz Etkinliği Eşleştirme", + "passphrase": "Passfrase (isteğe bağlı)", "password": "Parola", "paste": "Yapıştır", "pause_wallet_creation": "Haven Cüzdanı oluşturma yeteneği şu anda duraklatıldı.", diff --git a/res/values/strings_uk.arb b/res/values/strings_uk.arb index 5d1e2be05..d3f1c5088 100644 --- a/res/values/strings_uk.arb +++ b/res/values/strings_uk.arb @@ -411,6 +411,7 @@ "outputs": "Виходи", "overwrite_amount": "Overwrite amount", "pairingInvalidEvent": "Недійсна подія сполучення", + "passphrase": "Пасофрази (необов’язково)", "password": "Пароль", "paste": "Вставити", "pause_wallet_creation": "Можливість створення гаманця Haven зараз призупинено.", diff --git a/res/values/strings_ur.arb b/res/values/strings_ur.arb index d98a85753..97851b210 100644 --- a/res/values/strings_ur.arb +++ b/res/values/strings_ur.arb @@ -413,6 +413,7 @@ "outputs": "نتائج", "overwrite_amount": "رقم کو اوور رائٹ کریں۔", "pairingInvalidEvent": "ﭧﻧﻮﯾﺍ ﻂﻠﻏ ﺎﻧﺎﻨﺑ ﺍﮌﻮﺟ", + "passphrase": "پاسفریز (اختیاری)", "password": "پاس ورڈ", "paste": "چسپاں کریں۔", "pause_wallet_creation": "Haven Wallet ۔ﮯﮨ ﻑﻮﻗﻮﻣ ﻝﺎﺤﻟﺍ ﯽﻓ ﺖﯿﻠﮨﺍ ﯽﮐ ﮯﻧﺎﻨﺑ", diff --git a/res/values/strings_yo.arb b/res/values/strings_yo.arb index faaeb8837..acb533536 100644 --- a/res/values/strings_yo.arb +++ b/res/values/strings_yo.arb @@ -412,6 +412,7 @@ "outputs": "Awọn iṣan", "overwrite_amount": "Pààrọ̀ iye owó", "pairingInvalidEvent": "Pipọpọ Iṣẹlẹ Ti ko tọ", + "passphrase": "Ọrọ kukuru (iyan)", "password": "Ọ̀rọ̀ aṣínà", "paste": "Fikún ẹ̀dà yín", "pause_wallet_creation": "Agbara lati ṣẹda Haven Wallet ti wa ni idaduro lọwọlọwọ.", diff --git a/res/values/strings_zh.arb b/res/values/strings_zh.arb index 2d5251d86..e17c4a89b 100644 --- a/res/values/strings_zh.arb +++ b/res/values/strings_zh.arb @@ -411,6 +411,7 @@ "outputs": "输出", "overwrite_amount": "Overwrite amount", "pairingInvalidEvent": "配对无效事件", + "passphrase": "密码(可选)", "password": "密码", "paste": "粘贴", "pause_wallet_creation": "创建 Haven 钱包的功能当前已暂停。", diff --git a/tool/configure.dart b/tool/configure.dart index 3b73bfe80..ceb0c9ccc 100644 --- a/tool/configure.dart +++ b/tool/configure.dart @@ -61,6 +61,8 @@ Future main(List args) async { Future generateBitcoin(bool hasImplementation) async { final outputFile = File(bitcoinOutputPath); const bitcoinCommonHeaders = """ +import 'dart:typed_data'; +import 'package:cw_core/node.dart'; import 'package:cw_core/pending_transaction.dart'; import 'package:cw_core/receive_page_option.dart'; import 'package:cw_core/unspent_transaction_output.dart'; @@ -73,8 +75,17 @@ import 'package:cw_core/wallet_service.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:cake_wallet/view_model/send/output.dart'; import 'package:hive/hive.dart'; -import 'package:bitcoin_base/bitcoin_base.dart';"""; +import 'package:bitcoin_base/bitcoin_base.dart'; +import 'package:bitcoin_flutter/bitcoin_flutter.dart' as btc; +import 'package:bip32/bip32.dart' as bip32; +import 'package:bip39/bip39.dart' as bip39; +import 'package:hive/hive.dart'; +"""; const bitcoinCWHeaders = """ +import 'package:cw_bitcoin/utils.dart'; +import 'package:cw_bitcoin/litecoin_network.dart'; +import 'package:cw_bitcoin/electrum_derivations.dart'; +import 'package:cw_bitcoin/electrum.dart'; import 'package:cw_bitcoin/pending_bitcoin_transaction.dart'; import 'package:cw_bitcoin/bitcoin_receive_page_option.dart'; import 'package:cw_bitcoin/electrum_wallet.dart'; @@ -87,6 +98,7 @@ import 'package:cw_bitcoin/bitcoin_amount_format.dart'; import 'package:cw_bitcoin/bitcoin_address_record.dart'; import 'package:cw_bitcoin/bitcoin_transaction_credentials.dart'; import 'package:cw_bitcoin/litecoin_wallet_service.dart'; +import 'package:cw_bitcoin/script_hash.dart'; import 'package:cw_bitcoin/pending_bitcoin_transaction.dart'; import 'package:mobx/mobx.dart'; """; @@ -112,7 +124,14 @@ import 'package:mobx/mobx.dart'; abstract class Bitcoin { TransactionPriority getMediumTransactionPriority(); - WalletCredentials createBitcoinRestoreWalletFromSeedCredentials({required String name, required String mnemonic, required String password}); + WalletCredentials createBitcoinRestoreWalletFromSeedCredentials({ + required String name, + required String mnemonic, + required String password, + required DerivationType derivationType, + required String derivationPath, + String? passphrase, + }); WalletCredentials createBitcoinRestoreWalletFromWIFCredentials({required String name, required String password, required String wif, WalletInfo? walletInfo}); WalletCredentials createBitcoinNewWalletCredentials({required String name, WalletInfo? walletInfo}); List getWordList(); @@ -147,7 +166,10 @@ abstract class Bitcoin { TransactionPriority getLitecoinTransactionPriorityMedium(); TransactionPriority getBitcoinTransactionPrioritySlow(); TransactionPriority getLitecoinTransactionPrioritySlow(); - + Future> compareDerivationMethods( + {required String mnemonic, required Node node}); + Future> getDerivationsFromMnemonic( + {required String mnemonic, required Node node, String? passphrase}); Future setAddressType(Object wallet, dynamic option); ReceivePageOption getSelectedAddressType(Object wallet); List getBitcoinReceivePageOptions(); @@ -838,14 +860,14 @@ abstract class Nano { required String name, required String password, required String mnemonic, - DerivationType? derivationType, + required DerivationType derivationType, }); WalletCredentials createNanoRestoreWalletFromKeysCredentials({ required String name, required String password, required String seedKey, - DerivationType? derivationType, + required DerivationType derivationType, }); List getNanoWordList(String language); @@ -892,6 +914,11 @@ abstract class NanoUtil { String? privateKey, required Node node, }); + Future> getDerivationsFromMnemonic({ + String? mnemonic, + String? seedKey, + required Node node, + }); } """; From f9e9b1d67ea2c21aa891cf3eb95803f47ac78058 Mon Sep 17 00:00:00 2001 From: Omar Hatem Date: Tue, 30 Apr 2024 04:05:48 +0300 Subject: [PATCH 17/17] update versions (#1418) --- assets/text/Monerocom_Release_Notes.txt | 3 +-- assets/text/Release_Notes.txt | 10 +++------- lib/src/screens/send/send_page.dart | 2 +- scripts/android/app_env.sh | 8 ++++---- scripts/ios/app_env.sh | 8 ++++---- scripts/macos/app_env.sh | 8 ++++---- 6 files changed, 17 insertions(+), 22 deletions(-) diff --git a/assets/text/Monerocom_Release_Notes.txt b/assets/text/Monerocom_Release_Notes.txt index 09092a8df..d5297ebe1 100644 --- a/assets/text/Monerocom_Release_Notes.txt +++ b/assets/text/Monerocom_Release_Notes.txt @@ -1,2 +1 @@ -UI enhancements -Bug fixes \ No newline at end of file +Generic bug fixes and enhancements \ No newline at end of file diff --git a/assets/text/Release_Notes.txt b/assets/text/Release_Notes.txt index 69a5145c9..ac648921c 100644 --- a/assets/text/Release_Notes.txt +++ b/assets/text/Release_Notes.txt @@ -1,7 +1,3 @@ -Add Replace-By-Fee to boost pending Bitcoin transactions -Enable WalletConnect for Solana -WalletConnect Enhancements -Enhancements for ERC-20 tokens and Solana tokens -Enhancements for Nano wallet -UI enhancements -Bug fixes \ No newline at end of file +Support restoring Non-Electrum Bitcoin Wallets (check supported derivation paths https://github.com/cake-tech/cake_wallet/blob/main/cw_bitcoin/lib/bitcoin_derivations.dart) +Bitcoin enhancements and bug fixes +Generic bug fixes and enhancements \ No newline at end of file diff --git a/lib/src/screens/send/send_page.dart b/lib/src/screens/send/send_page.dart index 93fadea72..9067a2951 100644 --- a/lib/src/screens/send/send_page.dart +++ b/lib/src/screens/send/send_page.dart @@ -102,7 +102,7 @@ class SendPage extends BasePage { double _sendCardHeight(BuildContext context) { double initialHeight = 480; if (sendViewModel.hasCoinControl) { - initialHeight += 35; + initialHeight += 55; } if (!responsiveLayoutUtil.shouldRenderMobileUI) { diff --git a/scripts/android/app_env.sh b/scripts/android/app_env.sh index c55be8900..5e52d9d96 100644 --- a/scripts/android/app_env.sh +++ b/scripts/android/app_env.sh @@ -15,15 +15,15 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN) APP_ANDROID_TYPE=$1 MONERO_COM_NAME="Monero.com" -MONERO_COM_VERSION="1.12.2" -MONERO_COM_BUILD_NUMBER=82 +MONERO_COM_VERSION="1.12.3" +MONERO_COM_BUILD_NUMBER=84 MONERO_COM_BUNDLE_ID="com.monero.app" MONERO_COM_PACKAGE="com.monero.app" MONERO_COM_SCHEME="monero.com" CAKEWALLET_NAME="Cake Wallet" -CAKEWALLET_VERSION="4.15.4" -CAKEWALLET_BUILD_NUMBER=204 +CAKEWALLET_VERSION="4.15.5" +CAKEWALLET_BUILD_NUMBER=206 CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet" CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet" CAKEWALLET_SCHEME="cakewallet" diff --git a/scripts/ios/app_env.sh b/scripts/ios/app_env.sh index b9dc0e435..6f5e810eb 100644 --- a/scripts/ios/app_env.sh +++ b/scripts/ios/app_env.sh @@ -13,13 +13,13 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN) APP_IOS_TYPE=$1 MONERO_COM_NAME="Monero.com" -MONERO_COM_VERSION="1.12.2" -MONERO_COM_BUILD_NUMBER=79 +MONERO_COM_VERSION="1.12.3" +MONERO_COM_BUILD_NUMBER=82 MONERO_COM_BUNDLE_ID="com.cakewallet.monero" CAKEWALLET_NAME="Cake Wallet" -CAKEWALLET_VERSION="4.15.4" -CAKEWALLET_BUILD_NUMBER=228 +CAKEWALLET_VERSION="4.15.5" +CAKEWALLET_BUILD_NUMBER=231 CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet" HAVEN_NAME="Haven" diff --git a/scripts/macos/app_env.sh b/scripts/macos/app_env.sh index 42708f3e3..309213b4a 100755 --- a/scripts/macos/app_env.sh +++ b/scripts/macos/app_env.sh @@ -16,13 +16,13 @@ if [ -n "$1" ]; then fi MONERO_COM_NAME="Monero.com" -MONERO_COM_VERSION="1.2.2" -MONERO_COM_BUILD_NUMBER=13 +MONERO_COM_VERSION="1.2.3" +MONERO_COM_BUILD_NUMBER=16 MONERO_COM_BUNDLE_ID="com.cakewallet.monero" CAKEWALLET_NAME="Cake Wallet" -CAKEWALLET_VERSION="1.8.4" -CAKEWALLET_BUILD_NUMBER=63 +CAKEWALLET_VERSION="1.8.5" +CAKEWALLET_BUILD_NUMBER=66 CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet" if ! [[ " ${TYPES[*]} " =~ " ${APP_MACOS_TYPE} " ]]; then