diff --git a/cw_core/lib/get_height_by_date.dart b/cw_core/lib/get_height_by_date.dart index 819990e0a..a680e6c25 100644 --- a/cw_core/lib/get_height_by_date.dart +++ b/cw_core/lib/get_height_by_date.dart @@ -84,7 +84,41 @@ final dates = { "2020-8": 2153983, "2020-9": 2176466, "2020-10": 2198453, - "2020-11": 2220000 + "2020-11": 2220000, + "2020-12": 2242240, + "2021-1": 2264584, + "2021-2": 2286892, + "2021-3": 2307079, + "2021-4": 2329385, + "2021-5": 2351004, + "2021-6": 2373306, + "2021-7": 2394882, + "2021-8": 2417162, + "2021-9": 2439490, + "2021-10": 2461020, + "2021-11": 2483377, + "2021-12": 2504932, + "2022-1": 2527316, + "2022-2": 2549605, + "2022-3": 2569711, + "2022-4": 2591995, + "2022-5": 2613603, + "2022-6": 2635840, + "2022-7": 2657395, + "2022-8": 2679705, + "2022-9": 2701991, + "2022-10": 2723607, + "2022-11": 2745899, + "2022-12": 2767427, + "2023-1": 2789763, + "2023-2": 2811996, + "2023-3": 2832118, + "2023-4": 2854365, + "2023-5": 2875972, + "2023-6": 2898234, + "2023-7": 2919771, + "2023-8": 2942045, + "2023-9": 2964280 }; int getMoneroHeigthByDate({required DateTime date}) { diff --git a/cw_core/pubspec.lock b/cw_core/pubspec.lock index 058f33ba4..f351759ed 100644 --- a/cw_core/pubspec.lock +++ b/cw_core/pubspec.lock @@ -271,10 +271,10 @@ packages: dependency: "direct dev" description: name: hive_generator - sha256: "81fd20125cb2ce8fd23623d7744ffbaf653aae93706c9bd3bf7019ea0ace3938" + sha256: "06cb8f58ace74de61f63500564931f9505368f45f98958bd7a6c35ba24159db4" url: "https://pub.dev" source: hosted - version: "1.1.3" + version: "2.0.1" http: dependency: "direct main" description: diff --git a/cw_core/pubspec.yaml b/cw_core/pubspec.yaml index 3763a7318..533b578ad 100644 --- a/cw_core/pubspec.yaml +++ b/cw_core/pubspec.yaml @@ -31,7 +31,7 @@ dev_dependencies: build_runner: ^2.1.11 build_resolvers: ^2.0.9 mobx_codegen: ^2.0.7 - hive_generator: ^1.1.3 + 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_monero/example/pubspec.lock b/cw_monero/example/pubspec.lock index 661341e96..3dd2b5b61 100644 --- a/cw_monero/example/pubspec.lock +++ b/cw_monero/example/pubspec.lock @@ -301,10 +301,19 @@ packages: dependency: transitive description: name: pointycastle - sha256: db7306cf0249f838d1a24af52b5a5887c5bf7f31d8bb4e827d071dc0939ad346 + sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" url: "https://pub.dev" source: hosted - version: "3.6.2" + version: "3.7.3" + polyseed: + dependency: transitive + description: + path: "." + ref: HEAD + resolved-ref: "504d58a5b147fccd3bc85a25f2e72fb32771ddd7" + url: "https://github.com/cake-tech/polyseed_dart.git" + source: git + version: "0.0.1" process: dependency: transitive description: @@ -416,5 +425,5 @@ packages: source: hosted version: "0.2.0+3" sdks: - dart: ">=3.0.0 <4.0.0" + dart: ">=3.0.6 <4.0.0" flutter: ">=3.7.0" diff --git a/cw_monero/ios/Classes/monero_api.cpp b/cw_monero/ios/Classes/monero_api.cpp index a0712255a..7ad873647 100644 --- a/cw_monero/ios/Classes/monero_api.cpp +++ b/cw_monero/ios/Classes/monero_api.cpp @@ -374,6 +374,35 @@ extern "C" return true; } + bool restore_wallet_from_spend_key(char *path, char *password, char *seed, char *language, char *spendKey, int32_t networkType, uint64_t restoreHeight, char *error) + { + Monero::NetworkType _networkType = static_cast(networkType); + Monero::Wallet *wallet = Monero::WalletManagerFactory::getWalletManager()->createDeterministicWalletFromSpendKey( + std::string(path), + std::string(password), + std::string(language), + _networkType, + (uint64_t)restoreHeight, + std::string(spendKey)); + + int status; + std::string errorString; + + wallet->statusWithErrorString(status, errorString); + + if (status != Monero::Wallet::Status_Ok || !errorString.empty()) + { + error = strdup(errorString.c_str()); + return false; + } + + // Cache Raw to support Polyseed + wallet->setCacheAttribute("cakewallet.seed", std::string(seed)); + + change_current_wallet(wallet); + return true; + } + bool load_wallet(char *path, char *password, int32_t nettype) { nice(19); @@ -438,6 +467,11 @@ extern "C" const char *seed() { + std::string _rawSeed = get_current_wallet()->getCacheAttribute("cakewallet.seed"); + if (!_rawSeed.empty()) + { + return strdup(_rawSeed.c_str()); + } return strdup(get_current_wallet()->seed().c_str()); } diff --git a/cw_monero/lib/api/signatures.dart b/cw_monero/lib/api/signatures.dart index 9be828df0..17099db91 100644 --- a/cw_monero/lib/api/signatures.dart +++ b/cw_monero/lib/api/signatures.dart @@ -14,6 +14,9 @@ typedef restore_wallet_from_seed = Int8 Function( typedef restore_wallet_from_keys = Int8 Function(Pointer, Pointer, Pointer, Pointer, Pointer, Pointer, Int32, Int64, Pointer); +typedef restore_wallet_from_spend_key = Int8 Function(Pointer, Pointer, Pointer, + Pointer, Pointer, Int32, Int64, Pointer); + typedef is_wallet_exist = Int8 Function(Pointer); typedef load_wallet = Int8 Function(Pointer, Pointer, Int8); diff --git a/cw_monero/lib/api/types.dart b/cw_monero/lib/api/types.dart index 4c0c980dc..1d3904870 100644 --- a/cw_monero/lib/api/types.dart +++ b/cw_monero/lib/api/types.dart @@ -14,6 +14,9 @@ typedef RestoreWalletFromSeed = int Function( typedef RestoreWalletFromKeys = int Function(Pointer, Pointer, Pointer, Pointer, Pointer, Pointer, int, int, Pointer); +typedef RestoreWalletFromSpendKey = int Function(Pointer, Pointer, Pointer, + Pointer, Pointer, int, int, Pointer); + typedef IsWalletExist = int Function(Pointer); typedef LoadWallet = int Function(Pointer, Pointer, int); diff --git a/cw_monero/lib/api/wallet_manager.dart b/cw_monero/lib/api/wallet_manager.dart index 093d7e63b..260b420c5 100644 --- a/cw_monero/lib/api/wallet_manager.dart +++ b/cw_monero/lib/api/wallet_manager.dart @@ -5,7 +5,6 @@ import 'package:cw_monero/api/convert_utf8_to_string.dart'; import 'package:cw_monero/api/signatures.dart'; import 'package:cw_monero/api/types.dart'; import 'package:cw_monero/api/monero_api.dart'; -import 'package:cw_monero/api/wallet.dart'; import 'package:cw_monero/api/exceptions/wallet_opening_exception.dart'; import 'package:cw_monero/api/exceptions/wallet_creation_exception.dart'; import 'package:cw_monero/api/exceptions/wallet_restore_from_keys_exception.dart'; @@ -25,6 +24,11 @@ final restoreWalletFromKeysNative = moneroApi 'restore_wallet_from_keys') .asFunction(); +final restoreWalletFromSpendKeyNative = moneroApi + .lookup>( + 'restore_wallet_from_spend_key') + .asFunction(); + final isWalletExistNative = moneroApi .lookup>('is_wallet_exist') .asFunction(); @@ -141,6 +145,42 @@ void restoreWalletFromKeysSync( } } +void restoreWalletFromSpendKeySync( + {required String path, + required String password, + required String seed, + required String language, + required String spendKey, + int nettype = 0, + int restoreHeight = 0}) { + final pathPointer = path.toNativeUtf8(); + final passwordPointer = password.toNativeUtf8(); + final seedPointer = seed.toNativeUtf8(); + final languagePointer = language.toNativeUtf8(); + final spendKeyPointer = spendKey.toNativeUtf8(); + final errorMessagePointer = ''.toNativeUtf8(); + final isWalletRestored = restoreWalletFromSpendKeyNative( + pathPointer, + passwordPointer, + seedPointer, + languagePointer, + spendKeyPointer, + nettype, + restoreHeight, + errorMessagePointer) != + 0; + + calloc.free(pathPointer); + calloc.free(passwordPointer); + calloc.free(languagePointer); + calloc.free(spendKeyPointer); + + if (!isWalletRestored) { + throw WalletRestoreFromKeysException( + message: convertUTF8ToString(pointer: errorMessagePointer)); + } +} + void loadWallet({ required String path, required String password, @@ -194,6 +234,23 @@ void _restoreFromKeys(Map args) { spendKey: spendKey); } +void _restoreFromSpendKey(Map args) { + final path = args['path'] as String; + final password = args['password'] as String; + final seed = args['seed'] as String; + final language = args['language'] as String; + final spendKey = args['spendKey'] as String; + final restoreHeight = args['restoreHeight'] as int; + + restoreWalletFromSpendKeySync( + path: path, + password: password, + seed: seed, + language: language, + restoreHeight: restoreHeight, + spendKey: spendKey); +} + Future _openWallet(Map args) async => loadWallet(path: args['path'] as String, password: args['password'] as String); @@ -251,4 +308,22 @@ Future restoreFromKeys( 'restoreHeight': restoreHeight }); +Future restoreFromSpendKey( + {required String path, + required String password, + required String seed, + required String language, + required String spendKey, + int nettype = 0, + int restoreHeight = 0}) async => + compute, void>(_restoreFromSpendKey, { + 'path': path, + 'password': password, + 'seed': seed, + 'language': language, + 'spendKey': spendKey, + 'nettype': nettype, + 'restoreHeight': restoreHeight + }); + Future isWalletExist({required String path}) => compute(_isWalletExist, path); diff --git a/cw_monero/lib/monero_wallet.dart b/cw_monero/lib/monero_wallet.dart index d7e66ecec..71c7e3967 100644 --- a/cw_monero/lib/monero_wallet.dart +++ b/cw_monero/lib/monero_wallet.dart @@ -29,6 +29,7 @@ import 'package:cw_monero/monero_transaction_info.dart'; import 'package:cw_monero/monero_unspent.dart'; import 'package:cw_monero/monero_wallet_addresses.dart'; import 'package:cw_monero/pending_monero_transaction.dart'; +import 'package:flutter/foundation.dart'; import 'package:hive/hive.dart'; import 'package:mobx/mobx.dart'; @@ -78,6 +79,8 @@ abstract class MoneroWalletBase Box unspentCoinsInfo; + void Function(FlutterErrorDetails)? _onError; + @override late MoneroWalletAddresses walletAddresses; @@ -388,46 +391,59 @@ abstract class MoneroWalletBase } Future updateUnspent() async { - refreshCoins(walletAddresses.account!.id); + try { + refreshCoins(walletAddresses.account!.id); - unspentCoins.clear(); + unspentCoins.clear(); - final coinCount = countOfCoins(); - for (var i = 0; i < coinCount; i++) { - final coin = getCoin(i); - if (coin.spent == 0) { - final unspent = MoneroUnspent.fromCoinsInfoRow(coin); - unspent.isChange = transaction_history.getTransaction(unspent.hash).direction == 1; - unspentCoins.add(unspent); - } - } - - if (unspentCoinsInfo.isEmpty) { - unspentCoins.forEach((coin) => _addCoinInfo(coin)); - return; - } - - if (unspentCoins.isNotEmpty) { - unspentCoins.forEach((coin) { - final coinInfoList = unspentCoinsInfo.values.where((element) => - element.walletId.contains(id) && - element.accountIndex == walletAddresses.account!.id && - element.keyImage!.contains(coin.keyImage!)); - - if (coinInfoList.isNotEmpty) { - final coinInfo = coinInfoList.first; - - coin.isFrozen = coinInfo.isFrozen; - coin.isSending = coinInfo.isSending; - coin.note = coinInfo.note; - } else { - _addCoinInfo(coin); + final coinCount = countOfCoins(); + for (var i = 0; i < coinCount; i++) { + final coin = getCoin(i); + if (coin.spent == 0) { + final unspent = MoneroUnspent.fromCoinsInfoRow(coin); + if (unspent.hash.isNotEmpty) { + unspent.isChange = transaction_history + .getTransaction(unspent.hash) + .direction == 1; + } + unspentCoins.add(unspent); } - }); - } + } - await _refreshUnspentCoinsInfo(); - _askForUpdateBalance(); + if (unspentCoinsInfo.isEmpty) { + unspentCoins.forEach((coin) => _addCoinInfo(coin)); + return; + } + + if (unspentCoins.isNotEmpty) { + unspentCoins.forEach((coin) { + final coinInfoList = unspentCoinsInfo.values.where((element) => + element.walletId.contains(id) && + element.accountIndex == walletAddresses.account!.id && + element.keyImage!.contains(coin.keyImage!)); + + if (coinInfoList.isNotEmpty) { + final coinInfo = coinInfoList.first; + + coin.isFrozen = coinInfo.isFrozen; + coin.isSending = coinInfo.isSending; + coin.note = coinInfo.note; + } else { + _addCoinInfo(coin); + } + }); + } + + await _refreshUnspentCoinsInfo(); + _askForUpdateBalance(); + } catch (e, s) { + print(e.toString()); + _onError?.call(FlutterErrorDetails( + exception: e, + stack: s, + library: this.runtimeType.toString(), + )); + } } Future _addCoinInfo(MoneroUnspent coin) async { @@ -632,4 +648,7 @@ abstract class MoneroWalletBase walletAddresses.updateSubaddressList(accountIndex: account?.id ?? 0); } } + + @override + void setExceptionHandler(void Function(FlutterErrorDetails) onError) => _onError = onError; } diff --git a/cw_monero/lib/monero_wallet_service.dart b/cw_monero/lib/monero_wallet_service.dart index 8cb3aa948..8e9eb6eac 100644 --- a/cw_monero/lib/monero_wallet_service.dart +++ b/cw_monero/lib/monero_wallet_service.dart @@ -7,16 +7,20 @@ import 'package:cw_core/wallet_credentials.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_service.dart'; import 'package:cw_core/wallet_type.dart'; +import 'package:cw_core/get_height_by_date.dart'; import 'package:cw_monero/api/exceptions/wallet_opening_exception.dart'; import 'package:cw_monero/api/wallet_manager.dart' as monero_wallet_manager; import 'package:cw_monero/monero_wallet.dart'; import 'package:hive/hive.dart'; +import 'package:polyseed/polyseed.dart'; +import 'package:polyseed/src/utils/key_utils.dart'; class MoneroNewWalletCredentials extends WalletCredentials { - MoneroNewWalletCredentials({required String name, required this.language, String? password}) + MoneroNewWalletCredentials({required String name, required this.language, required this.isPolyseed, String? password}) : super(name: name, password: password); final String language; + final bool isPolyseed; } class MoneroRestoreWalletFromSeedCredentials extends WalletCredentials { @@ -68,10 +72,17 @@ class MoneroWalletService extends WalletService< Future create(MoneroNewWalletCredentials credentials) async { try { final path = await pathForWallet(name: credentials.name, type: getType()); + + if (credentials.isPolyseed) { + final polyseed = Polyseed.create(); + final lang = PolyseedLang.getByEnglishName(credentials.language); + + return _restoreFromPolyseed( + path, credentials.password!, polyseed, credentials.walletInfo!, lang); + } + await monero_wallet_manager.createWallet( - path: path, - password: credentials.password!, - language: credentials.language); + path: path, password: credentials.password!, language: credentials.language); final wallet = MoneroWallet( walletInfo: credentials.walletInfo!, unspentCoinsInfo: unspentCoinsInfoSource); await wallet.init(); @@ -215,6 +226,12 @@ class MoneroWalletService extends WalletService< @override Future restoreFromSeed( MoneroRestoreWalletFromSeedCredentials credentials) async { + + // Restore from Polyseed + if (Polyseed.isValidSeed(credentials.mnemonic)) { + return restoreFromPolyseed(credentials); + } + try { final path = await pathForWallet(name: credentials.name, type: getType()); await monero_wallet_manager.restoreFromSeed( @@ -234,6 +251,42 @@ class MoneroWalletService extends WalletService< } } + Future restoreFromPolyseed(MoneroRestoreWalletFromSeedCredentials credentials) async { + try { + final path = await pathForWallet(name: credentials.name, type: getType()); + final polyseedCoin = PolyseedCoin.POLYSEED_MONERO; + final lang = PolyseedLang.getByPhrase(credentials.mnemonic); + final polyseed = Polyseed.decode(credentials.mnemonic, lang, polyseedCoin); + + return _restoreFromPolyseed(path, credentials.password!, polyseed, credentials.walletInfo!, lang); + } catch (e) { + // TODO: Implement Exception for wallet list service. + print('MoneroWalletsManager Error: $e'); + rethrow; + } + } + + Future _restoreFromPolyseed(String path, String password, Polyseed polyseed, + WalletInfo walletInfo, PolyseedLang lang, + {PolyseedCoin coin = PolyseedCoin.POLYSEED_MONERO}) async { + final height = getMoneroHeigthByDate( + date: DateTime.fromMillisecondsSinceEpoch(polyseed.birthday * 1000)); + final spendKey = keyToHexString(polyseed.generateKey(coin, 32)); + + await monero_wallet_manager.restoreFromSpendKey( + path: path, + password: password, + seed: polyseed.encode(lang, coin), + language: lang.nameEnglish, + restoreHeight: height, + spendKey: spendKey); + final wallet = MoneroWallet( + walletInfo: walletInfo, unspentCoinsInfo: unspentCoinsInfoSource); + await wallet.init(); + + return wallet; + } + Future repairOldAndroidWallet(String name) async { try { if (!Platform.isAndroid) { diff --git a/cw_monero/pubspec.lock b/cw_monero/pubspec.lock index dc0f9aeed..46ebe8028 100644 --- a/cw_monero/pubspec.lock +++ b/cw_monero/pubspec.lock @@ -478,10 +478,19 @@ packages: dependency: transitive description: name: pointycastle - sha256: db7306cf0249f838d1a24af52b5a5887c5bf7f31d8bb4e827d071dc0939ad346 + sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" url: "https://pub.dev" source: hosted - version: "3.6.2" + version: "3.7.3" + polyseed: + dependency: "direct main" + description: + path: "." + ref: HEAD + resolved-ref: "504d58a5b147fccd3bc85a25f2e72fb32771ddd7" + url: "https://github.com/cake-tech/polyseed_dart.git" + source: git + version: "0.0.1" pool: dependency: transitive description: @@ -689,5 +698,5 @@ packages: source: hosted version: "3.1.1" sdks: - dart: ">=3.0.0 <4.0.0" + dart: ">=3.0.6 <4.0.0" flutter: ">=3.7.0" diff --git a/cw_monero/pubspec.yaml b/cw_monero/pubspec.yaml index cf2993ef3..55e9b354c 100644 --- a/cw_monero/pubspec.yaml +++ b/cw_monero/pubspec.yaml @@ -19,6 +19,9 @@ dependencies: flutter_mobx: ^2.0.6+1 intl: ^0.18.0 encrypt: ^5.0.1 + polyseed: + git: + url: https://github.com/cake-tech/polyseed_dart.git cw_core: path: ../cw_core diff --git a/lib/entities/preferences_key.dart b/lib/entities/preferences_key.dart index 85df63b69..bdd6c24a7 100644 --- a/lib/entities/preferences_key.dart +++ b/lib/entities/preferences_key.dart @@ -64,6 +64,7 @@ class PreferencesKey { static const exchangeProvidersSelection = 'exchange-providers-selection'; static const autoGenerateSubaddressStatusKey = 'auto_generate_subaddress_status'; + static const moneroSeedType = 'monero_seed_type'; static const clearnetDonationLink = 'clearnet_donation_link'; static const onionDonationLink = 'onion_donation_link'; static const lastSeenAppVersion = 'last_seen_app_version'; diff --git a/lib/entities/seed_type.dart b/lib/entities/seed_type.dart new file mode 100644 index 000000000..0a1a191c6 --- /dev/null +++ b/lib/entities/seed_type.dart @@ -0,0 +1,36 @@ +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cw_core/enumerable_item.dart'; + +class SeedType extends EnumerableItem with Serializable { + const SeedType({required String title, required int raw}) : super(title: title, raw: raw); + + static const all = [SeedType.legacy, SeedType.polyseed]; + + static const defaultSeedType = legacy; + + static const legacy = SeedType(raw: 0, title: 'Legacy (25 words)'); + static const polyseed = SeedType(raw: 1, title: 'Polyseed (16 words)'); + + static SeedType deserialize({required int raw}) { + switch (raw) { + case 0: + return legacy; + case 1: + return polyseed; + default: + throw Exception('Unexpected token: $raw for SeedType deserialize'); + } + } + + @override + String toString() { + switch (this) { + case SeedType.legacy: + return S.current.seedtype_legacy; + case SeedType.polyseed: + return S.current.seedtype_polyseed; + default: + return ''; + } + } +} diff --git a/lib/monero/cw_monero.dart b/lib/monero/cw_monero.dart index 9ae248ca0..947d274a8 100644 --- a/lib/monero/cw_monero.dart +++ b/lib/monero/cw_monero.dart @@ -166,6 +166,10 @@ class CWMonero extends Monero { @override List getMoneroWordList(String language) { + if (language.startsWith("POLYSEED_")) { + final lang = language.replaceAll("POLYSEED_", ""); + return PolyseedLang.getByEnglishName(lang).words; + } switch (language.toLowerCase()) { case 'english': return EnglishMnemonics.words; @@ -223,8 +227,10 @@ class CWMonero extends Monero { WalletCredentials createMoneroNewWalletCredentials({ required String name, required String language, + required bool isPolyseed, String? password}) => - MoneroNewWalletCredentials(name: name, password: password, language: language); + MoneroNewWalletCredentials( + name: name, password: password, language: language, isPolyseed: isPolyseed); @override Map getKeys(Object wallet) { diff --git a/lib/router.dart b/lib/router.dart index fb21ba32c..313751ab3 100644 --- a/lib/router.dart +++ b/lib/router.dart @@ -56,6 +56,7 @@ import 'package:cake_wallet/src/screens/support_other_links/support_other_links_ import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_details_page.dart'; import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_list_page.dart'; import 'package:cake_wallet/src/screens/wallet_connect/wc_connections_listing_view.dart'; +import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/utils/payment_request.dart'; import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart'; import 'package:cake_wallet/view_model/dashboard/nft_view_model.dart'; @@ -87,7 +88,6 @@ import 'package:cake_wallet/src/screens/setup_pin_code/setup_pin_code.dart'; import 'package:cake_wallet/src/screens/restore/restore_options_page.dart'; import 'package:cake_wallet/src/screens/send/send_page.dart'; import 'package:cake_wallet/src/screens/disclaimer/disclaimer_page.dart'; -import 'package:cake_wallet/src/screens/seed_language/seed_language_page.dart'; import 'package:cake_wallet/src/screens/transaction_details/transaction_details_page.dart'; import 'package:cake_wallet/src/screens/monero_accounts/monero_account_edit_or_create_page.dart'; import 'package:cake_wallet/src/screens/contact/contact_list_page.dart'; @@ -147,8 +147,9 @@ Route createRoute(RouteSettings settings) { case Routes.newWallet: final type = settings.arguments as WalletType; final walletNewVM = getIt.get(param1: type); + final settingsStore = getIt.get(); - return CupertinoPageRoute(builder: (_) => NewWalletPage(walletNewVM)); + return CupertinoPageRoute(builder: (_) => NewWalletPage(walletNewVM, settingsStore)); case Routes.setupPin: Function(PinCodeState, String)? callback; @@ -264,17 +265,6 @@ Route createRoute(RouteSettings settings) { case Routes.changeRep: return CupertinoPageRoute(builder: (_) => getIt.get()); - case Routes.seedLanguage: - final args = settings.arguments as List; - final type = args.first as WalletType; - final redirectRoute = args[1] as String; - - return CupertinoPageRoute(builder: (_) { - return SeedLanguage( - onConfirm: (context, lang) => - Navigator.of(context).popAndPushNamed(redirectRoute, arguments: [type, lang])); - }); - case Routes.walletList: return MaterialPageRoute( fullscreenDialog: true, builder: (_) => getIt.get()); diff --git a/lib/routes.dart b/lib/routes.dart index 4511d48e1..60801297a 100644 --- a/lib/routes.dart +++ b/lib/routes.dart @@ -18,7 +18,6 @@ class Routes { static const disclaimer = '/disclaimer'; static const readDisclaimer = '/read_disclaimer'; static const changeRep = '/change_representative'; - static const seedLanguage = '/seed_language'; static const walletList = '/view_model.wallet_list'; static const auth = '/auth'; static const newNode = '/new_node_list'; diff --git a/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart b/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart index 66a28042d..4b61e7889 100644 --- a/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart +++ b/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart @@ -1,6 +1,7 @@ import 'package:cake_wallet/entities/exchange_api_mode.dart'; import 'package:cake_wallet/entities/fiat_api_mode.dart'; import 'package:cake_wallet/entities/seed_phrase_length.dart'; +import 'package:cake_wallet/entities/seed_type.dart'; import 'package:cake_wallet/src/screens/nodes/widgets/node_form.dart'; import 'package:cake_wallet/src/screens/settings/widgets/settings_choices_cell.dart'; import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.dart'; @@ -97,16 +98,27 @@ class _AdvancedPrivacySettingsBodyState extends State( - title: S.current.seed_phrase_length, - items: SeedPhraseLength.values, - selectedItem: widget.privacySettingsViewModel.seedPhraseLength, - onItemSelected: (SeedPhraseLength length) { - widget.privacySettingsViewModel.setSeedPhraseLength(length); - }, - ); - }), + Observer(builder: (_) { + return SettingsPickerCell( + title: S.current.seed_phrase_length, + items: SeedPhraseLength.values, + selectedItem: widget.privacySettingsViewModel.seedPhraseLength, + onItemSelected: (SeedPhraseLength length) { + widget.privacySettingsViewModel.setSeedPhraseLength(length); + }, + ); + }), + if (widget.privacySettingsViewModel.hasSeedTypeOption) + Observer(builder: (_) { + return SettingsChoicesCell( + ChoicesListItem( + title: S.current.seedtype, + items: SeedType.all, + selectedItem: widget.privacySettingsViewModel.seedType, + onItemSelected: widget.privacySettingsViewModel.setSeedType, + ), + ); + }), ], ), bottomSectionPadding: EdgeInsets.all(24), diff --git a/lib/src/screens/new_wallet/new_wallet_page.dart b/lib/src/screens/new_wallet/new_wallet_page.dart index 5577fcd88..d86d51e93 100644 --- a/lib/src/screens/new_wallet/new_wallet_page.dart +++ b/lib/src/screens/new_wallet/new_wallet_page.dart @@ -14,17 +14,20 @@ import 'package:cake_wallet/src/widgets/seed_language_selector.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/widgets/primary_button.dart'; import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; -import 'package:cake_wallet/src/screens/seed_language/widgets/seed_language_picker.dart'; +import 'package:cake_wallet/src/widgets/seed_language_picker.dart'; import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; import 'package:cake_wallet/core/execution_state.dart'; import 'package:cake_wallet/view_model/wallet_new_vm.dart'; import 'package:cake_wallet/themes/extensions/new_wallet_theme.dart'; import 'package:cake_wallet/themes/extensions/send_page_theme.dart'; +import 'package:cake_wallet/entities/seed_type.dart'; +import 'package:cake_wallet/store/settings_store.dart'; class NewWalletPage extends BasePage { - NewWalletPage(this._walletNewVM); + NewWalletPage(this._walletNewVM, this._settingsStore); final WalletNewVM _walletNewVM; + final SettingsStore _settingsStore; final walletNameImage = Image.asset('assets/images/wallet_name.png'); @@ -35,14 +38,15 @@ class NewWalletPage extends BasePage { @override Widget body(BuildContext context) => WalletNameForm( - _walletNewVM, currentTheme.type == ThemeType.dark ? walletNameImage : walletNameLightImage); + _walletNewVM, currentTheme.type == ThemeType.dark ? walletNameImage : walletNameLightImage, _settingsStore); } class WalletNameForm extends StatefulWidget { - WalletNameForm(this._walletNewVM, this.walletImage); + WalletNameForm(this._walletNewVM, this.walletImage, this._settingsStore); final WalletNewVM _walletNewVM; final Image walletImage; + final SettingsStore _settingsStore; @override _WalletNameFormState createState() => _WalletNameFormState(_walletNewVM); @@ -125,15 +129,20 @@ class _WalletNameFormState extends State { hintStyle: TextStyle( fontSize: 18.0, fontWeight: FontWeight.w500, - color: Theme.of(context).extension()!.hintTextColor), + color: + Theme.of(context).extension()!.hintTextColor), hintText: S.of(context).wallet_name, focusedBorder: UnderlineInputBorder( borderSide: BorderSide( - color: Theme.of(context).extension()!.underlineColor, + color: Theme.of(context) + .extension()! + .underlineColor, width: 1.0)), enabledBorder: UnderlineInputBorder( borderSide: BorderSide( - color: Theme.of(context).extension()!.underlineColor, + color: Theme.of(context) + .extension()! + .underlineColor, width: 1.0), ), suffixIcon: Semantics( @@ -160,7 +169,9 @@ class _WalletNameFormState extends State { height: 34, child: Image.asset( 'assets/images/refresh_icon.png', - color: Theme.of(context).extension()!.textFieldButtonIconColor, + color: Theme.of(context) + .extension()! + .textFieldButtonIconColor, ), ), ), @@ -184,10 +195,15 @@ class _WalletNameFormState extends State { color: Theme.of(context).extension()!.titleColor), ), ), - Padding( - padding: EdgeInsets.only(top: 24), - child: SeedLanguageSelector( - key: _languageSelectorKey, initialSelected: defaultSeedLanguage), + Observer( + builder: (BuildContext build) => Padding( + padding: EdgeInsets.only(top: 24), + child: SeedLanguageSelector( + key: _languageSelectorKey, + initialSelected: defaultSeedLanguage, + seedType: widget._settingsStore.moneroSeedType, + ), + ), ) ] ], @@ -237,9 +253,10 @@ class _WalletNameFormState extends State { buttonAction: () => Navigator.of(context).pop()); }); } else { + final isPolyseed = widget._settingsStore.moneroSeedType == SeedType.polyseed; _walletNewVM.create( options: _walletNewVM.hasLanguageSelector - ? _languageSelectorKey.currentState!.selected + ? [_languageSelectorKey.currentState!.selected, isPolyseed] : null); } } 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 d10277ced..ac8413212 100644 --- a/lib/src/screens/restore/wallet_restore_from_seed_form.dart +++ b/lib/src/screens/restore/wallet_restore_from_seed_form.dart @@ -1,17 +1,17 @@ +import 'package:cake_wallet/core/wallet_name_validator.dart'; import 'package:cake_wallet/entities/generate_name.dart'; -import 'package:cw_core/wallet_type.dart'; -import 'package:cake_wallet/view_model/wallet_restore_view_model.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:cake_wallet/utils/show_pop_up.dart'; -import 'package:cake_wallet/src/screens/seed_language/widgets/seed_language_picker.dart'; -import 'package:cake_wallet/src/widgets/seed_widget.dart'; +import 'package:cake_wallet/entities/seed_type.dart'; +import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/src/widgets/base_text_form_field.dart'; import 'package:cake_wallet/src/widgets/blockchain_height_widget.dart'; -import 'package:cake_wallet/src/widgets/base_text_form_field.dart'; -import 'package:cake_wallet/generated/i18n.dart'; -import 'package:cake_wallet/core/wallet_name_validator.dart'; +import 'package:cake_wallet/src/widgets/picker.dart'; +import 'package:cake_wallet/src/widgets/seed_language_picker.dart'; +import 'package:cake_wallet/src/widgets/seed_widget.dart'; import 'package:cake_wallet/themes/extensions/send_page_theme.dart'; +import 'package:cake_wallet/utils/show_pop_up.dart'; +import 'package:cw_core/wallet_type.dart'; +import 'package:flutter/material.dart'; +import 'package:polyseed/polyseed.dart'; class WalletRestoreFromSeedForm extends StatefulWidget { WalletRestoreFromSeedForm( @@ -34,8 +34,7 @@ class WalletRestoreFromSeedForm extends StatefulWidget { final void Function(String)? onLanguageChange; @override - WalletRestoreFromSeedFormState createState() => - WalletRestoreFromSeedFormState('English'); + WalletRestoreFromSeedFormState createState() => WalletRestoreFromSeedFormState('English'); } class WalletRestoreFromSeedFormState extends State { @@ -44,77 +43,116 @@ class WalletRestoreFromSeedFormState extends State { blockchainHeightKey = GlobalKey(), formKey = GlobalKey(), languageController = TextEditingController(), - nameTextEditingController = TextEditingController(); + nameTextEditingController = TextEditingController(), + seedTypeController = TextEditingController(); final GlobalKey seedWidgetStateKey; final GlobalKey blockchainHeightKey; final TextEditingController languageController; final TextEditingController nameTextEditingController; + final TextEditingController seedTypeController; final GlobalKey formKey; String language; + bool isPolyseed = false; @override void initState() { _setLanguageLabel(language); + _setSeedType(SeedType.defaultSeedType); super.initState(); } + void onSeedChange(String seed) { + if (widget.type == WalletType.monero && Polyseed.isValidSeed(seed)) { + final lang = PolyseedLang.getByPhrase(seed); + + _changeSeedType(SeedType.polyseed); + _changeLanguage(lang.nameEnglish); + } + widget.onSeedChange?.call(seed); + } + @override Widget build(BuildContext context) { return Container( padding: EdgeInsets.only(left: 24, right: 24), child: Column(children: [ Form( - key: formKey, - child: Stack( - alignment: Alignment.centerRight, - children: [ - BaseTextFormField( - controller: nameTextEditingController, - hintText: S.of(context).wallet_name, - suffixIcon: IconButton( - onPressed: () async { - final rName = await generateName(); - FocusManager.instance.primaryFocus?.unfocus(); + key: formKey, + child: Stack( + alignment: Alignment.centerRight, + children: [ + BaseTextFormField( + controller: nameTextEditingController, + hintText: S.of(context).wallet_name, + suffixIcon: IconButton( + onPressed: () async { + final rName = await generateName(); + FocusManager.instance.primaryFocus?.unfocus(); - setState(() { - nameTextEditingController.text = rName; - nameTextEditingController.selection = - TextSelection.fromPosition(TextPosition( - offset: nameTextEditingController.text.length)); - }); - }, - icon: Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(6.0), - color: Theme.of(context).hintColor, - ), - width: 34, - height: 34, - child: Image.asset( - 'assets/images/refresh_icon.png', - color: Theme.of(context).extension()!.textFieldButtonIconColor, + setState(() { + nameTextEditingController.text = rName; + nameTextEditingController.selection = TextSelection.fromPosition( + TextPosition(offset: nameTextEditingController.text.length)); + }); + }, + icon: Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(6.0), + color: Theme.of(context).hintColor, + ), + width: 34, + height: 34, + child: Image.asset( + 'assets/images/refresh_icon.png', + color: Theme.of(context) + .extension()! + .textFieldButtonIconColor, + ), + ), ), + validator: WalletNameValidator(), ), - ), - validator: WalletNameValidator(), - ), - ], - )), + ], + )), Container(height: 20), SeedWidget( key: seedWidgetStateKey, language: language, type: widget.type, - onSeedChange: widget.onSeedChange), + onSeedChange: onSeedChange), + if (widget.type == WalletType.monero) + GestureDetector( + onTap: () async { + await showPopUp( + context: context, + builder: (_) => Picker( + items: SeedType.all, + selectedAtIndex: isPolyseed ? 1 : 0, + mainAxisAlignment: MainAxisAlignment.start, + onItemSelected: _changeSeedType, + isSeparated: false, + )); + }, + child: Container( + color: Colors.transparent, + padding: EdgeInsets.only(top: 20.0), + child: IgnorePointer( + child: BaseTextFormField( + controller: seedTypeController, + enableInteractiveSelection: false, + readOnly: true)))), if (widget.displayLanguageSelector) GestureDetector( onTap: () async { await showPopUp( context: context, builder: (_) => SeedLanguagePicker( - selected: language, onItemSelected: _changeLanguage)); + selected: language, + onItemSelected: _changeLanguage, + seedType: isPolyseed ? SeedType.polyseed : SeedType.legacy, + )); }, child: Container( color: Colors.transparent, @@ -124,24 +162,35 @@ class WalletRestoreFromSeedFormState extends State { controller: languageController, enableInteractiveSelection: false, readOnly: true)))), - if (widget.displayBlockHeightSelector) + if (!isPolyseed && widget.displayBlockHeightSelector) BlockchainHeightWidget( focusNode: widget.blockHeightFocusNode, key: blockchainHeightKey, onHeightOrDateEntered: widget.onHeightOrDateEntered, - hasDatePicker: widget.type == WalletType.monero) + hasDatePicker: widget.type == WalletType.monero), ])); } void _changeLanguage(String language) { + final setLang = isPolyseed ? "POLYSEED_$language" : language; setState(() { - this.language = language; - seedWidgetStateKey.currentState!.changeSeedLanguage(language); - _setLanguageLabel(language); - widget.onLanguageChange?.call(language); + this.language = setLang; + seedWidgetStateKey.currentState!.changeSeedLanguage(setLang); + _setLanguageLabel(setLang); + widget.onLanguageChange?.call(setLang); }); } void _setLanguageLabel(String language) => - languageController.text = '$language (Seed language)'; + languageController.text = '${language.replaceAll("POLYSEED_", "")} (Seed language)'; + + void _changeSeedType(SeedType item) { + _setSeedType(item); + _changeLanguage('English'); + } + + void _setSeedType(SeedType item) { + setState(() => isPolyseed = item == SeedType.polyseed); + seedTypeController.text = item.toString(); + } } diff --git a/lib/src/screens/restore/wallet_restore_page.dart b/lib/src/screens/restore/wallet_restore_page.dart index d77c8aa2a..ccac6f34c 100644 --- a/lib/src/screens/restore/wallet_restore_page.dart +++ b/lib/src/screens/restore/wallet_restore_page.dart @@ -1,29 +1,30 @@ +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'; +import 'package:cake_wallet/src/screens/restore/wallet_restore_from_seed_form.dart'; +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/src/widgets/keyboard_done_button.dart'; +import 'package:cake_wallet/themes/extensions/wallet_list_theme.dart'; import 'package:cake_wallet/utils/responsive_layout_util.dart'; +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/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'; +import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:keyboard_actions/keyboard_actions.dart'; import 'package:mobx/mobx.dart'; -import 'package:flutter_mobx/flutter_mobx.dart'; +import 'package:polyseed/polyseed.dart'; import 'package:smooth_page_indicator/smooth_page_indicator.dart'; -import 'package:cake_wallet/generated/i18n.dart'; -import 'package:cake_wallet/core/execution_state.dart'; -import 'package:cake_wallet/src/screens/base_page.dart'; -import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; -import 'package:cake_wallet/view_model/wallet_restore_view_model.dart'; -import 'package:cake_wallet/src/screens/restore/wallet_restore_from_keys_form.dart'; -import 'package:cake_wallet/src/screens/restore/wallet_restore_from_seed_form.dart'; -import 'package:cake_wallet/src/widgets/primary_button.dart'; -import 'package:cake_wallet/utils/show_pop_up.dart'; -import 'package:cake_wallet/view_model/restore/restore_mode.dart'; -import 'package:cake_wallet/themes/extensions/wallet_list_theme.dart'; class WalletRestorePage extends BasePage { WalletRestorePage(this.walletRestoreViewModel) @@ -48,27 +49,13 @@ class WalletRestorePage extends BasePage { } }, onSeedChange: (String seed) { - if (walletRestoreViewModel.hasBlockchainHeightLanguageSelector) { - final hasHeight = walletRestoreFromSeedFormKey.currentState!.blockchainHeightKey - .currentState!.restoreHeightController.text.isNotEmpty; - if (hasHeight) { - walletRestoreViewModel.isButtonEnabled = _isValidSeed(); - } - } else { - walletRestoreViewModel.isButtonEnabled = _isValidSeed(); - } + final isPolyseed = + walletRestoreViewModel.type == WalletType.monero && Polyseed.isValidSeed(seed); + _validateOnChange(isPolyseed: isPolyseed); }, - onLanguageChange: (_) { - if (walletRestoreViewModel.hasBlockchainHeightLanguageSelector) { - final hasHeight = walletRestoreFromSeedFormKey.currentState!.blockchainHeightKey - .currentState!.restoreHeightController.text.isNotEmpty; - - if (hasHeight) { - walletRestoreViewModel.isButtonEnabled = _isValidSeed(); - } - } else { - walletRestoreViewModel.isButtonEnabled = _isValidSeed(); - } + onLanguageChange: (String language) { + final isPolyseed = language.startsWith("POLYSEED_"); + _validateOnChange(isPolyseed: isPolyseed); })); break; case WalletRestoreMode.keys: @@ -163,7 +150,8 @@ class WalletRestorePage extends BasePage { color: Theme.of(context).colorScheme.background, child: Center( child: ConstrainedBox( - constraints: BoxConstraints(maxWidth: ResponsiveLayoutUtilBase.kDesktopMaxWidthConstraint), + constraints: + BoxConstraints(maxWidth: ResponsiveLayoutUtilBase.kDesktopMaxWidthConstraint), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ @@ -219,8 +207,8 @@ class WalletRestorePage extends BasePage { const SizedBox(height: 25), GestureDetector( onTap: () { - Navigator.of(context) - .pushNamed(Routes.advancedPrivacySettings, arguments: walletRestoreViewModel.type); + Navigator.of(context).pushNamed(Routes.advancedPrivacySettings, + arguments: walletRestoreViewModel.type); }, child: Text(S.of(context).advanced_privacy_settings), ), @@ -235,9 +223,26 @@ class WalletRestorePage extends BasePage { ); } + void _validateOnChange({bool isPolyseed = false}) { + if (!isPolyseed && walletRestoreViewModel.hasBlockchainHeightLanguageSelector) { + final hasHeight = walletRestoreFromSeedFormKey + .currentState?.blockchainHeightKey.currentState?.restoreHeightController.text.isNotEmpty; + + if (hasHeight == true) { + walletRestoreViewModel.isButtonEnabled = _isValidSeed(); + } + } else { + walletRestoreViewModel.isButtonEnabled = _isValidSeed(); + } + } + bool _isValidSeed() { - final seedWords = - walletRestoreFromSeedFormKey.currentState!.seedWidgetStateKey.currentState!.text.split(' '); + final seedPhrase = + walletRestoreFromSeedFormKey.currentState!.seedWidgetStateKey.currentState!.text; + if (walletRestoreViewModel.type == WalletType.monero && Polyseed.isValidSeed(seedPhrase)) + return true; + + final seedWords = seedPhrase.split(' '); if ((walletRestoreViewModel.type == WalletType.monero || walletRestoreViewModel.type == WalletType.haven) && @@ -282,7 +287,8 @@ class WalletRestorePage extends BasePage { if (walletRestoreViewModel.hasBlockchainHeightLanguageSelector) { credentials['height'] = - walletRestoreFromSeedFormKey.currentState!.blockchainHeightKey.currentState!.height; + walletRestoreFromSeedFormKey.currentState!.blockchainHeightKey.currentState?.height ?? + -1; } credentials['name'] = diff --git a/lib/src/screens/seed_language/seed_language_page.dart b/lib/src/screens/seed_language/seed_language_page.dart deleted file mode 100644 index b15da0375..000000000 --- a/lib/src/screens/seed_language/seed_language_page.dart +++ /dev/null @@ -1,95 +0,0 @@ -import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; -import 'package:cake_wallet/themes/theme_base.dart'; -import 'package:cake_wallet/src/widgets/seed_language_selector.dart'; -import 'package:flutter_mobx/flutter_mobx.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:cake_wallet/generated/i18n.dart'; -import 'package:cake_wallet/src/screens/base_page.dart'; -import 'package:cake_wallet/src/widgets/primary_button.dart'; -import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; -import 'package:cake_wallet/src/screens/seed_language/widgets/seed_language_picker.dart'; - -class SeedLanguage extends BasePage { - SeedLanguage({required this.onConfirm}); - - final Function(BuildContext, String) onConfirm; - - final walletNameImage = Image.asset('assets/images/wallet_name.png'); - final walletNameLightImage = - Image.asset('assets/images/wallet_name_light.png'); - - @override - String get title => S.current.wallet_list_restore_wallet; - - @override - Widget body(BuildContext context) => - SeedLanguageForm( - onConfirm: onConfirm, - walletImage: currentTheme.type == ThemeType.dark - ? walletNameImage : walletNameLightImage); -} - -class SeedLanguageForm extends StatefulWidget { - SeedLanguageForm({required this.onConfirm, required this.walletImage}); - - final Function(BuildContext, String) onConfirm; - final Image walletImage; - - @override - SeedLanguageFormState createState() => SeedLanguageFormState(); -} - -class SeedLanguageFormState extends State { - static const aspectRatioImage = 1.22; - final _languageSelectorKey = GlobalKey(); - - @override - Widget build(BuildContext context) { - return Container( - padding: EdgeInsets.only(top: 24), - child: ScrollableWithBottomSection( - contentPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24), - content: - Column(crossAxisAlignment: CrossAxisAlignment.center, children: [ - Padding( - padding: EdgeInsets.only(left: 12, right: 12), - child: AspectRatio( - aspectRatio: aspectRatioImage, - child: FittedBox(child: widget.walletImage, - fit: BoxFit.fill)), - ), - Padding( - padding: EdgeInsets.only(top: 40), - child: Text( - S.of(context).seed_language_choose, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.w500, - color: - Theme.of(context).extension()!.titleColor), - ), - ), - Padding( - padding: EdgeInsets.only(top: 24), - child: SeedLanguageSelector( - key: _languageSelectorKey, - initialSelected: defaultSeedLanguage), - ) - ]), - bottomSectionPadding: - EdgeInsets.only(left: 24, right: 24, bottom: 24), - bottomSection: Observer( - builder: (context) { - return PrimaryButton( - onPressed: () => widget.onConfirm( - context, _languageSelectorKey.currentState!.selected), - text: S.of(context).seed_language_next, - color: Colors.green, - textColor: Colors.white); - }, - )), - ); - } -} diff --git a/lib/src/screens/seed_language/widgets/seed_language_picker.dart b/lib/src/screens/seed_language/widgets/seed_language_picker.dart deleted file mode 100644 index 742a31e61..000000000 --- a/lib/src/screens/seed_language/widgets/seed_language_picker.dart +++ /dev/null @@ -1,82 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:cake_wallet/src/widgets/picker.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:cake_wallet/generated/i18n.dart'; - -List flagImages = [ - Image.asset('assets/images/flags/usa.png'), - Image.asset('assets/images/flags/chn.png'), - Image.asset('assets/images/flags/nld.png'), - Image.asset('assets/images/flags/deu.png'), - Image.asset('assets/images/flags/jpn.png'), - Image.asset('assets/images/flags/prt.png'), - Image.asset('assets/images/flags/rus.png'), - Image.asset('assets/images/flags/esp.png'), - Image.asset('assets/images/flags/fra.png'), - Image.asset('assets/images/flags/ita.png'), -]; - -const List languageCodes = [ - 'Eng', - 'Chi', - 'Ned', - 'Ger', - 'Jap', - 'Por', - 'Rus', - 'Esp', - 'Fre', - 'Ita', -]; - -const defaultSeedLanguage = 'English'; - -const List seedLanguages = [ - defaultSeedLanguage, - 'Chinese (simplified)', - 'Dutch', - 'German', - 'Japanese', - 'Portuguese', - 'Russian', - 'Spanish', - 'French', - 'Italian', -]; - -enum Places { topLeft, topRight, bottomLeft, bottomRight, inside } - -class SeedLanguagePicker extends StatefulWidget { - SeedLanguagePicker({Key? key, this.selected = defaultSeedLanguage, required this.onItemSelected}) - : super(key: key); - - final String selected; - final Function(String) onItemSelected; - - @override - SeedLanguagePickerState createState() => - SeedLanguagePickerState(selected: selected, onItemSelected: onItemSelected); -} - -class SeedLanguagePickerState extends State { - SeedLanguagePickerState({required this.selected, required this.onItemSelected}); - - final String selected; - final Function(String) onItemSelected; - - @override - Widget build(BuildContext context) { - return Picker( - selectedAtIndex: seedLanguages.indexOf(selected), - items: seedLanguages, - images: flagImages, - isGridView: true, - title: S.of(context).seed_choose, - hintText: S.of(context).seed_choose, - matchingCriteria: (String language, String searchText) { - return language.toLowerCase().contains(searchText); - }, - onItemSelected: onItemSelected, - ); - } -} diff --git a/lib/src/widgets/seed_language_picker.dart b/lib/src/widgets/seed_language_picker.dart new file mode 100644 index 000000000..3bb0376b1 --- /dev/null +++ b/lib/src/widgets/seed_language_picker.dart @@ -0,0 +1,93 @@ +import 'package:flutter/material.dart'; +import 'package:cake_wallet/src/widgets/picker.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:cake_wallet/generated/i18n.dart'; + +import 'package:cake_wallet/entities/seed_type.dart'; + +class SeedLanguagePickerOption { + SeedLanguagePickerOption(this.name, this.nameLocalized, this.image, this.supportedSeedTypes); + + final String name; + final String nameLocalized; + final Image image; + final List supportedSeedTypes; +} + +final List seedLanguages = [ + SeedLanguagePickerOption('English', S.current.seed_language_english, + Image.asset('assets/images/flags/usa.png'), [SeedType.legacy, SeedType.polyseed]), + SeedLanguagePickerOption('Chinese (simplified)', S.current.seed_language_chinese, + Image.asset('assets/images/flags/chn.png'), [SeedType.legacy, SeedType.polyseed]), + SeedLanguagePickerOption('Chinese (Traditional)', S.current.seed_language_chinese_traditional, + Image.asset('assets/images/flags/chn.png'), [SeedType.polyseed]), + SeedLanguagePickerOption('Dutch', S.current.seed_language_dutch, + Image.asset('assets/images/flags/nld.png'), [SeedType.legacy]), + SeedLanguagePickerOption('German', S.current.seed_language_german, + Image.asset('assets/images/flags/deu.png'), [SeedType.legacy]), + SeedLanguagePickerOption('Japanese', S.current.seed_language_japanese, + Image.asset('assets/images/flags/jpn.png'), [SeedType.legacy, SeedType.polyseed]), + SeedLanguagePickerOption('Korean', S.current.seed_language_korean, + Image.asset('assets/images/flags/kor.png'), [SeedType.polyseed]), + SeedLanguagePickerOption('Portuguese', S.current.seed_language_portuguese, + Image.asset('assets/images/flags/prt.png'), [SeedType.legacy, SeedType.polyseed]), + SeedLanguagePickerOption('Russian', S.current.seed_language_russian, + Image.asset('assets/images/flags/rus.png'), [SeedType.legacy]), + SeedLanguagePickerOption('Czech', S.current.seed_language_czech, + Image.asset('assets/images/flags/czk.png'), [SeedType.polyseed]), + SeedLanguagePickerOption('Spanish', S.current.seed_language_spanish, + Image.asset('assets/images/flags/esp.png'), [SeedType.legacy, SeedType.polyseed]), + SeedLanguagePickerOption('French', S.current.seed_language_french, + Image.asset('assets/images/flags/fra.png'), [SeedType.legacy, SeedType.polyseed]), + SeedLanguagePickerOption('Italian', S.current.seed_language_italian, + Image.asset('assets/images/flags/ita.png'), [SeedType.legacy, SeedType.polyseed]), +]; + +const defaultSeedLanguage = 'English'; + +enum Places { topLeft, topRight, bottomLeft, bottomRight, inside } + +class SeedLanguagePicker extends StatefulWidget { + SeedLanguagePicker( + {Key? key, + this.selected = defaultSeedLanguage, + this.seedType = SeedType.defaultSeedType, + required this.onItemSelected}) + : super(key: key); + + final SeedType seedType; + final String selected; + final Function(String) onItemSelected; + + @override + SeedLanguagePickerState createState() => SeedLanguagePickerState( + selected: selected, onItemSelected: onItemSelected, seedType: seedType); +} + +class SeedLanguagePickerState extends State { + SeedLanguagePickerState( + {required this.selected, required this.onItemSelected, required this.seedType}); + + final SeedType seedType; + final String selected; + final Function(String) onItemSelected; + + @override + Widget build(BuildContext context) { + final availableSeedLanguages = seedLanguages + .where((SeedLanguagePickerOption e) => e.supportedSeedTypes.contains(seedType)); + + return Picker( + selectedAtIndex: availableSeedLanguages.map((e) => e.name).toList().indexOf(selected), + items: availableSeedLanguages.map((e) => e.name).toList(), + images: availableSeedLanguages.map((e) => e.image).toList(), + isGridView: true, + title: S.of(context).seed_choose, + hintText: S.of(context).seed_choose, + matchingCriteria: (String language, String searchText) { + return language.toLowerCase().contains(searchText); + }, + onItemSelected: onItemSelected, + ); + } +} diff --git a/lib/src/widgets/seed_language_selector.dart b/lib/src/widgets/seed_language_selector.dart index 4db3684a8..07638bb2f 100644 --- a/lib/src/widgets/seed_language_selector.dart +++ b/lib/src/widgets/seed_language_selector.dart @@ -1,14 +1,15 @@ +import 'package:cake_wallet/entities/seed_type.dart'; +import 'package:cake_wallet/src/screens/new_wallet/widgets/select_button.dart'; +import 'package:cake_wallet/src/widgets/seed_language_picker.dart'; import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:flutter/material.dart'; -import 'package:cake_wallet/generated/i18n.dart'; -import 'package:cake_wallet/src/screens/new_wallet/widgets/select_button.dart'; -import 'package:cake_wallet/src/screens/seed_language/widgets/seed_language_picker.dart'; class SeedLanguageSelector extends StatefulWidget { - SeedLanguageSelector({Key? key, required this.initialSelected}) + SeedLanguageSelector({Key? key, required this.initialSelected, this.seedType = SeedType.defaultSeedType}) : super(key: key); final String initialSelected; + final SeedType seedType; @override SeedLanguageSelectorState createState() => @@ -18,30 +19,19 @@ class SeedLanguageSelector extends StatefulWidget { class SeedLanguageSelectorState extends State { SeedLanguageSelectorState({required this.selected}); - final seedLocales = [ - S.current.seed_language_english, - S.current.seed_language_chinese, - S.current.seed_language_dutch, - S.current.seed_language_german, - S.current.seed_language_japanese, - S.current.seed_language_portuguese, - S.current.seed_language_russian, - S.current.seed_language_spanish, - S.current.seed_language_french, - S.current.seed_language_italian, - ]; String selected; @override Widget build(BuildContext context) { return SelectButton( image: null, - text: seedLocales[seedLanguages.indexOf(selected)], + text: seedLanguages.firstWhere((e) => e.name == selected).nameLocalized, onTap: () async { await showPopUp( context: context, builder: (_) => SeedLanguagePicker( selected: this.selected, + seedType: widget.seedType, onItemSelected: (String selected) => setState(() => this.selected = selected))); }, diff --git a/lib/store/settings_store.dart b/lib/store/settings_store.dart index 1522ea354..4aaa44e13 100644 --- a/lib/store/settings_store.dart +++ b/lib/store/settings_store.dart @@ -10,6 +10,7 @@ import 'package:cake_wallet/entities/exchange_api_mode.dart'; import 'package:cake_wallet/entities/pin_code_required_duration.dart'; import 'package:cake_wallet/entities/preferences_key.dart'; import 'package:cake_wallet/entities/seed_phrase_length.dart'; +import 'package:cake_wallet/entities/seed_type.dart'; import 'package:cake_wallet/entities/sort_balance_types.dart'; import 'package:cake_wallet/exchange/provider/trocador_exchange_provider.dart'; import 'package:cake_wallet/view_model/settings/sync_mode.dart'; @@ -48,6 +49,7 @@ abstract class SettingsStoreBase with Store { required BalanceDisplayMode initialBalanceDisplayMode, required bool initialSaveRecipientAddress, required AutoGenerateSubaddressStatus initialAutoGenerateSubaddressStatus, + required SeedType initialMoneroSeedType, required bool initialAppSecure, required bool initialDisableBuy, required bool initialDisableSell, @@ -108,6 +110,7 @@ abstract class SettingsStoreBase with Store { balanceDisplayMode = initialBalanceDisplayMode, shouldSaveRecipientAddress = initialSaveRecipientAddress, autoGenerateSubaddressStatus = initialAutoGenerateSubaddressStatus, + moneroSeedType = initialMoneroSeedType, fiatApiMode = initialFiatMode, allowBiometricalAuthentication = initialAllowBiometricalAuthentication, selectedCake2FAPreset = initialCake2FAPresetOptions, @@ -240,6 +243,11 @@ abstract class SettingsStoreBase with Store { (AutoGenerateSubaddressStatus autoGenerateSubaddressStatus) => sharedPreferences.setInt( PreferencesKey.autoGenerateSubaddressStatusKey, autoGenerateSubaddressStatus.value)); + reaction( + (_) => moneroSeedType, + (SeedType moneroSeedType) => sharedPreferences.setInt( + PreferencesKey.moneroSeedType, moneroSeedType.raw)); + reaction( (_) => fiatApiMode, (FiatApiMode mode) => @@ -435,6 +443,7 @@ abstract class SettingsStoreBase with Store { static const defaultPinCodeTimeOutDuration = PinCodeRequiredDuration.tenminutes; static const defaultAutoGenerateSubaddressStatus = AutoGenerateSubaddressStatus.initialized; static const defaultSeedPhraseLength = SeedPhraseLength.twelveWords; + static const defaultMoneroSeedType = SeedType.defaultSeedType; @observable FiatCurrency fiatCurrency; @@ -460,6 +469,9 @@ abstract class SettingsStoreBase with Store { @observable AutoGenerateSubaddressStatus autoGenerateSubaddressStatus; + @observable + SeedType moneroSeedType; + @observable bool isAppSecure; @@ -775,12 +787,20 @@ abstract class SettingsStoreBase with Store { final packageInfo = await PackageInfo.fromPlatform(); final deviceName = await _getDeviceName() ?? ''; final shouldShowYatPopup = sharedPreferences.getBool(PreferencesKey.shouldShowYatPopup) ?? true; + final generateSubaddresses = sharedPreferences.getInt(PreferencesKey.autoGenerateSubaddressStatusKey); final autoGenerateSubaddressStatus = generateSubaddresses != null ? AutoGenerateSubaddressStatus.deserialize(raw: generateSubaddresses) : defaultAutoGenerateSubaddressStatus; + + final _moneroSeedType = sharedPreferences.getInt(PreferencesKey.moneroSeedType); + + final moneroSeedType = _moneroSeedType != null + ? SeedType.deserialize(raw: _moneroSeedType) + : defaultMoneroSeedType; + final nodes = {}; final powNodes = {}; @@ -833,27 +853,27 @@ abstract class SettingsStoreBase with Store { initialBalanceDisplayMode: currentBalanceDisplayMode, initialSaveRecipientAddress: shouldSaveRecipientAddress, initialAutoGenerateSubaddressStatus: autoGenerateSubaddressStatus, - initialAppSecure: isAppSecure, - initialDisableBuy: disableBuy, - initialDisableSell: disableSell, - initialDefaultBuyProvider: defaultBuyProvider, - initialFiatMode: currentFiatApiMode, - initialAllowBiometricalAuthentication: allowBiometricalAuthentication, - initialCake2FAPresetOptions: selectedCake2FAPreset, - initialUseTOTP2FA: useTOTP2FA, - initialTotpSecretKey: totpSecretKey, - initialFailedTokenTrial: tokenTrialNumber, - initialExchangeStatus: exchangeStatus, - initialTheme: savedTheme, - actionlistDisplayMode: actionListDisplayMode, - initialPinLength: pinLength, - pinTimeOutDuration: pinCodeTimeOutDuration, - seedPhraseLength: seedPhraseWordCount, - initialLanguageCode: savedLanguageCode, - sortBalanceBy: sortBalanceBy, - pinNativeTokenAtTop: pinNativeTokenAtTop, - useEtherscan: useEtherscan, - defaultNanoRep: defaultNanoRep, + initialMoneroSeedType: moneroSeedType, + initialAppSecure: isAppSecure, + initialDisableBuy: disableBuy, + initialDisableSell: disableSell, + initialDefaultBuyProvider: defaultBuyProvider, + initialFiatMode: currentFiatApiMode, + initialAllowBiometricalAuthentication: allowBiometricalAuthentication, + initialCake2FAPresetOptions: selectedCake2FAPreset, + initialUseTOTP2FA: useTOTP2FA, + initialTotpSecretKey: totpSecretKey, + initialFailedTokenTrial: tokenTrialNumber, + initialExchangeStatus: exchangeStatus, + initialTheme: savedTheme, + actionlistDisplayMode: actionListDisplayMode, + initialPinLength: pinLength, + pinTimeOutDuration: pinCodeTimeOutDuration, + seedPhraseLength: seedPhraseWordCount,initialLanguageCode: savedLanguageCode, + sortBalanceBy: sortBalanceBy, + pinNativeTokenAtTop: pinNativeTokenAtTop, + useEtherscan: useEtherscan, + defaultNanoRep: defaultNanoRep, defaultBananoRep: defaultBananoRep, lookupsTwitter: lookupsTwitter, lookupsMastodon: lookupsMastodon, @@ -862,10 +882,10 @@ abstract class SettingsStoreBase with Store { lookupsOpenAlias: lookupsOpenAlias, lookupsENS: lookupsENS, initialMoneroTransactionPriority: moneroTransactionPriority, - initialBitcoinTransactionPriority: bitcoinTransactionPriority, - initialHavenTransactionPriority: havenTransactionPriority, - initialLitecoinTransactionPriority: litecoinTransactionPriority, - initialBitcoinCashTransactionPriority: bitcoinCashTransactionPriority, + initialBitcoinTransactionPriority: bitcoinTransactionPriority, + initialHavenTransactionPriority: havenTransactionPriority, + initialLitecoinTransactionPriority: litecoinTransactionPriority, + initialBitcoinCashTransactionPriority: bitcoinCashTransactionPriority, initialShouldRequireTOTP2FAForAccessingWallet: shouldRequireTOTP2FAForAccessingWallet, initialShouldRequireTOTP2FAForSendsToContact: shouldRequireTOTP2FAForSendsToContact, initialShouldRequireTOTP2FAForSendsToNonContact: shouldRequireTOTP2FAForSendsToNonContact, @@ -927,6 +947,12 @@ abstract class SettingsStoreBase with Store { ? AutoGenerateSubaddressStatus.deserialize(raw: generateSubaddresses) : defaultAutoGenerateSubaddressStatus; + final _moneroSeedType = sharedPreferences.getInt(PreferencesKey.moneroSeedType); + + moneroSeedType = _moneroSeedType != null + ? SeedType.deserialize(raw: _moneroSeedType) + : defaultMoneroSeedType; + balanceDisplayMode = BalanceDisplayMode.deserialize( raw: sharedPreferences.getInt(PreferencesKey.currentBalanceDisplayModeKey)!); shouldSaveRecipientAddress = diff --git a/lib/view_model/advanced_privacy_settings_view_model.dart b/lib/view_model/advanced_privacy_settings_view_model.dart index b67a4378a..f62815346 100644 --- a/lib/view_model/advanced_privacy_settings_view_model.dart +++ b/lib/view_model/advanced_privacy_settings_view_model.dart @@ -1,6 +1,7 @@ import 'package:cake_wallet/entities/exchange_api_mode.dart'; import 'package:cake_wallet/entities/fiat_api_mode.dart'; import 'package:cake_wallet/entities/seed_phrase_length.dart'; +import 'package:cake_wallet/entities/seed_type.dart'; import 'package:cake_wallet/store/settings_store.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:mobx/mobx.dart'; @@ -19,6 +20,9 @@ abstract class AdvancedPrivacySettingsViewModelBase with Store { @computed FiatApiMode get fiatApiMode => _settingsStore.fiatApiMode; + @computed + SeedType get seedType => _settingsStore.moneroSeedType; + @observable bool _addCustomNode = false; @@ -29,6 +33,8 @@ abstract class AdvancedPrivacySettingsViewModelBase with Store { bool get hasSeedPhraseLengthOption => type == WalletType.bitcoinCash || type == WalletType.ethereum; + bool get hasSeedTypeOption => type == WalletType.monero; + @computed bool get addCustomNode => _addCustomNode; @@ -38,6 +44,9 @@ abstract class AdvancedPrivacySettingsViewModelBase with Store { @action void setFiatApiMode(FiatApiMode fiatApiMode) => _settingsStore.fiatApiMode = fiatApiMode; + @action + void setSeedType(SeedType seedType) => _settingsStore.moneroSeedType = seedType; + @action void setExchangeApiMode(ExchangeApiMode value) => _settingsStore.exchangeStatus = value; diff --git a/lib/view_model/restore/wallet_restore_from_qr_code.dart b/lib/view_model/restore/wallet_restore_from_qr_code.dart index 145db74d7..6085f4354 100644 --- a/lib/view_model/restore/wallet_restore_from_qr_code.dart +++ b/lib/view_model/restore/wallet_restore_from_qr_code.dart @@ -10,6 +10,7 @@ import 'package:cw_core/wallet_type.dart'; import 'package:flutter/cupertino.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:collection/collection.dart'; +import 'package:polyseed/polyseed.dart'; class WalletRestoreFromQRCode { WalletRestoreFromQRCode(); @@ -51,7 +52,7 @@ class WalletRestoreFromQRCode { RegExp _getPattern(int wordCount) => RegExp(r'(?<=\W|^)((?:\w+\s+){' + (wordCount - 1).toString() + r'}\w+)(?=\W|$)'); - List patternCounts = walletType == WalletType.monero ? [25, 14, 13] : [24, 18, 12]; + List patternCounts = walletType == WalletType.monero ? [25, 16, 14, 13] : [24, 18, 12]; for (final count in patternCounts) { final pattern = _getPattern(count); @@ -123,12 +124,17 @@ class WalletRestoreFromQRCode { } if (credentials['seed'] != null) { - final seedValue = credentials['seed']; + final seedValue = credentials['seed'] as String; final words = SeedValidator.getWordList(type: type, language: 'english'); + + if (type == WalletType.monero && Polyseed.isValidSeed(seedValue)) { + return WalletRestoreMode.seed; + } + seedValue.split(' ').forEach((element) { if (!words.contains(element)) { throw Exception( - 'Unexpected restore mode: mnemonic_seed is invalid or does\'t match wallet type'); + "Unexpected restore mode: mnemonic_seed is invalid or doesn't match wallet type"); } }); return WalletRestoreMode.seed; diff --git a/lib/view_model/wallet_new_vm.dart b/lib/view_model/wallet_new_vm.dart index 9b1f0834d..696559198 100644 --- a/lib/view_model/wallet_new_vm.dart +++ b/lib/view_model/wallet_new_vm.dart @@ -1,6 +1,4 @@ -import 'package:cake_wallet/view_model/restore/restore_wallet.dart'; import 'package:cake_wallet/ethereum/ethereum.dart'; -import 'package:flutter/foundation.dart'; import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart'; import 'package:hive/hive.dart'; import 'package:mobx/mobx.dart'; @@ -33,18 +31,19 @@ abstract class WalletNewVMBase extends WalletCreationVM with Store { bool get hasLanguageSelector => type == WalletType.monero || type == WalletType.haven; @override - WalletCredentials getCredentials(dynamic options) { + WalletCredentials getCredentials(dynamic _options) { + final options = _options as List; switch (type) { case WalletType.monero: return monero!.createMoneroNewWalletCredentials( - name: name, language: options as String); + name: name, language: options.first as String, isPolyseed: options.last as bool); case WalletType.bitcoin: return bitcoin!.createBitcoinNewWalletCredentials(name: name); case WalletType.litecoin: return bitcoin!.createBitcoinNewWalletCredentials(name: name); case WalletType.haven: return haven!.createHavenNewWalletCredentials( - name: name, language: options as String); + name: name, language: options.first as String); case WalletType.ethereum: return ethereum!.createEthereumNewWalletCredentials(name: name); case WalletType.bitcoinCash: diff --git a/pubspec_base.yaml b/pubspec_base.yaml index edfc64890..f71d38578 100644 --- a/pubspec_base.yaml +++ b/pubspec_base.yaml @@ -104,6 +104,9 @@ dependencies: ref: main socks5_proxy: ^1.0.4 flutter_svg: ^2.0.9 + polyseed: + git: + url: https://github.com/cake-tech/polyseed_dart.git dev_dependencies: flutter_test: diff --git a/res/values/strings_ar.arb b/res/values/strings_ar.arb index 8065a5bd1..47b11c78e 100644 --- a/res/values/strings_ar.arb +++ b/res/values/strings_ar.arb @@ -739,5 +739,11 @@ "unavailable_balance_description": ".ﺎﻫﺪﻴﻤﺠﺗ ءﺎﻐﻟﺇ ﺭﺮﻘﺗ ﻰﺘﺣ ﺕﻼﻣﺎﻌﻤﻠﻟ ﻝﻮﺻﻮﻠﻟ ﺔﻠﺑﺎﻗ ﺮﻴﻏ ﺓﺪﻤﺠﻤﻟﺍ ﺓﺪﺻﺭﻷﺍ ﻞﻈﺗ ﺎﻤﻨﻴﺑ ،ﺎﻬﺑ ﺔﺻﺎﺨﻟﺍ ﺕﻼﻣﺎﻌﻤﻟﺍ ﻝﺎﻤﺘﻛﺍ ﺩﺮﺠﻤﺑ ﺔﺣﺎﺘﻣ ﺔﻠﻔﻘﻤﻟﺍ ﺓﺪﺻﺭﻷﺍ ﺢﺒﺼﺘﺳ .ﻚﺑ ﺔﺻﺎﺨﻟﺍ ﺕﻼﻤﻌﻟﺍ ﻲﻓ ﻢﻜﺤﺘﻟﺍ ﺕﺍﺩﺍﺪﻋﺇ ﻲﻓ ﻂﺸﻧ ﻞﻜﺸﺑ ﺎﻫﺪﻴﻤﺠﺘﺑ ﺖﻤﻗ", "unspent_change": "يتغير", "seed_hex_form": "بذور المحفظة (شكل عرافة)", - "tor_connection": "ﺭﻮﺗ ﻝﺎﺼﺗﺍ" + "tor_connection": "ﺭﻮﺗ ﻝﺎﺼﺗﺍ", + "seedtype": "البذور", + "seedtype_legacy": "إرث (25 كلمة)", + "seedtype_polyseed": "بوليسيد (16 كلمة)", + "seed_language_czech": "التشيكية", + "seed_language_korean": "الكورية", + "seed_language_chinese_traditional": "تقاليد صينية)" } diff --git a/res/values/strings_bg.arb b/res/values/strings_bg.arb index ab45efba3..162e85cad 100644 --- a/res/values/strings_bg.arb +++ b/res/values/strings_bg.arb @@ -735,5 +735,11 @@ "unavailable_balance_description": "Неналично салдо: Тази обща сума включва средства, които са заключени в чакащи транзакции и тези, които сте замразили активно в настройките за контрол на монетите. Заключените баланси ще станат достъпни, след като съответните им транзакции бъдат завършени, докато замразените баланси остават недостъпни за транзакции, докато не решите да ги размразите.", "unspent_change": "Промяна", "tor_connection": "Tor връзка", - "seed_hex_form": "Семена от портфейл (шестнадесетична форма)" + "seed_hex_form": "Семена от портфейл (шестнадесетична форма)", + "seedtype": "Семенна тип", + "seedtype_legacy": "Наследство (25 думи)", + "seedtype_polyseed": "Поли семе (16 думи)", + "seed_language_czech": "Чех", + "seed_language_korean": "Корейски", + "seed_language_chinese_traditional": "Традиционен китайски)" } \ No newline at end of file diff --git a/res/values/strings_cs.arb b/res/values/strings_cs.arb index 88792ec15..8efdb59b5 100644 --- a/res/values/strings_cs.arb +++ b/res/values/strings_cs.arb @@ -735,5 +735,11 @@ "unavailable_balance_description": "Nedostupný zůstatek: Tento součet zahrnuje prostředky, které jsou uzamčeny v nevyřízených transakcích a ty, které jste aktivně zmrazili v nastavení kontroly mincí. Uzamčené zůstatky budou k dispozici po dokončení příslušných transakcí, zatímco zmrazené zůstatky zůstanou pro transakce nepřístupné, dokud se nerozhodnete je uvolnit.", "unspent_change": "Změna", "tor_connection": "Připojení Tor", - "seed_hex_form": "Semeno peněženky (hex formulář)" + "seed_hex_form": "Semeno peněženky (hex formulář)", + "seedtype": "SeedType", + "seedtype_legacy": "Legacy (25 slov)", + "seedtype_polyseed": "Polyseed (16 slov)", + "seed_language_czech": "čeština", + "seed_language_korean": "korejština", + "seed_language_chinese_traditional": "Číňan (tradiční)" } \ No newline at end of file diff --git a/res/values/strings_de.arb b/res/values/strings_de.arb index 7b204f20c..754a0f22e 100644 --- a/res/values/strings_de.arb +++ b/res/values/strings_de.arb @@ -722,9 +722,9 @@ "awaitDAppProcessing": "Bitte warten Sie, bis die dApp die Verarbeitung abgeschlossen hat.", "copyWalletConnectLink": "Kopieren Sie den WalletConnect-Link von dApp und fügen Sie ihn hier ein", "enterWalletConnectURI": "Geben Sie den WalletConnect-URI ein", - "seed_key": "Samenschlüssel", - "enter_seed_phrase": "Geben Sie Ihre Samenphrase ein", - "change_rep_successful": "Erfolgreich veränderte Vertreter", + "seed_key": "Seed-Schlüssel", + "enter_seed_phrase": "Geben Sie Ihre Seed-Phrase ein", + "change_rep_successful": "Vertreter erfolgreich gerändert", "add_contact": "Kontakt hinzufügen", "exchange_provider_unsupported": "${providerName} wird nicht mehr unterstützt!", "domain_looks_up": "Domain-Suchen", @@ -743,5 +743,11 @@ "unavailable_balance_description": "Nicht verfügbares Guthaben: Diese Summe umfasst Gelder, die in ausstehenden Transaktionen gesperrt sind, und solche, die Sie in Ihren Münzkontrolleinstellungen aktiv eingefroren haben. Gesperrte Guthaben werden verfügbar, sobald die entsprechenden Transaktionen abgeschlossen sind, während eingefrorene Guthaben für Transaktionen nicht zugänglich bleiben, bis Sie sich dazu entschließen, sie wieder freizugeben.", "unspent_change": "Wechselgeld", "tor_connection": "Tor-Verbindung", - "seed_hex_form": "Brieftaschensamen (Sechskantform)" + "seed_hex_form": "Brieftaschensamen (Sechskantform)", + "seedtype": "Seedtyp", + "seedtype_legacy": "Veraltet (25 Wörter)", + "seedtype_polyseed": "Polyseed (16 Wörter)", + "seed_language_czech": "Tschechisch", + "seed_language_korean": "Koreanisch", + "seed_language_chinese_traditional": "Chinesisch (Traditionell)" } \ No newline at end of file diff --git a/res/values/strings_en.arb b/res/values/strings_en.arb index bbcbdb6c0..d65aebe15 100644 --- a/res/values/strings_en.arb +++ b/res/values/strings_en.arb @@ -744,5 +744,11 @@ "unavailable_balance_description": "Unavailable Balance: This total includes funds that are locked in pending transactions and those you have actively frozen in your coin control settings. Locked balances will become available once their respective transactions are completed, while frozen balances remain inaccessible for transactions until you decide to unfreeze them.", "unspent_change": "Change", "tor_connection": "Tor connection", - "seed_hex_form": "Wallet seed (hex form)" + "seed_hex_form": "Wallet seed (hex form)", + "seedtype": "Seedtype", + "seedtype_legacy": "Legacy (25 words)", + "seedtype_polyseed": "Polyseed (16 words)", + "seed_language_czech": "Czech", + "seed_language_korean": "Korean", + "seed_language_chinese_traditional": "Chinese (Traditional)" } \ No newline at end of file diff --git a/res/values/strings_es.arb b/res/values/strings_es.arb index e47f3e744..f785a15d5 100644 --- a/res/values/strings_es.arb +++ b/res/values/strings_es.arb @@ -743,5 +743,11 @@ "unavailable_balance_description": "Saldo no disponible: este total incluye fondos que están bloqueados en transacciones pendientes y aquellos que usted ha congelado activamente en su configuración de control de monedas. Los saldos bloqueados estarán disponibles una vez que se completen sus respectivas transacciones, mientras que los saldos congelados permanecerán inaccesibles para las transacciones hasta que usted decida descongelarlos.", "unspent_change": "Cambiar", "tor_connection": "conexión tor", - "seed_hex_form": "Semilla de billetera (forma hexadecimal)" + "seed_hex_form": "Semilla de billetera (forma hexadecimal)", + "seedtype": "Type de semillas", + "seedtype_legacy": "Legado (25 palabras)", + "seedtype_polyseed": "Polieta (16 palabras)", + "seed_language_czech": "checo", + "seed_language_korean": "coreano", + "seed_language_chinese_traditional": "Chino tradicional)" } \ No newline at end of file diff --git a/res/values/strings_fr.arb b/res/values/strings_fr.arb index f87ed9809..88263ec05 100644 --- a/res/values/strings_fr.arb +++ b/res/values/strings_fr.arb @@ -745,5 +745,12 @@ "switchToETHWallet": "Veuillez passer à un portefeuille (wallet) Ethereum et réessayer", "unspent_change": "Changement", "tor_connection": "Connexion Tor", - "seed_hex_form": "Graine du portefeuille (forme hexagonale)" + "seed_hex_form": "Graine du portefeuille (forme hexagonale)", + "camera_permission_is_required": "L'autorisation de la caméra est requise.\nVeuillez l'activer à partir des paramètres de l'application.", + "seedtype": "Type de type graine", + "seedtype_legacy": "Héritage (25 mots)", + "seedtype_polyseed": "Polyseed (16 mots)", + "seed_language_czech": "tchèque", + "seed_language_korean": "coréen", + "seed_language_chinese_traditional": "Chinois (Traditionnel)" } \ No newline at end of file diff --git a/res/values/strings_ha.arb b/res/values/strings_ha.arb index 2dce6f80d..39b98b51a 100644 --- a/res/values/strings_ha.arb +++ b/res/values/strings_ha.arb @@ -721,5 +721,11 @@ "unavailable_balance_description": "Ma'auni Babu: Wannan jimlar ya haɗa da kuɗi waɗanda ke kulle a cikin ma'amaloli da ke jiran aiki da waɗanda kuka daskare sosai a cikin saitunan sarrafa kuɗin ku. Ma'auni da aka kulle za su kasance da zarar an kammala ma'amalolinsu, yayin da daskararrun ma'auni ba za su iya samun damar yin ciniki ba har sai kun yanke shawarar cire su.", "unspent_change": "Canza", "tor_connection": "Tor haɗin gwiwa", - "seed_hex_form": "Gany Sero (form form)" + "seed_hex_form": "Gany Sero (form form)", + "seedtype": "Seedtype", + "seedtype_legacy": "Legacy (25 kalmomi)", + "seedtype_polyseed": "Polyseed (16 kalmomi)", + "seed_language_czech": "Czech", + "seed_language_korean": "Yaren Koriya", + "seed_language_chinese_traditional": "Sinanci (na gargajiya)" } \ No newline at end of file diff --git a/res/values/strings_hi.arb b/res/values/strings_hi.arb index 66a4c8e47..b050ef43b 100644 --- a/res/values/strings_hi.arb +++ b/res/values/strings_hi.arb @@ -743,5 +743,11 @@ "unavailable_balance_description": "अनुपलब्ध शेष राशि: इस कुल में वे धनराशि शामिल हैं जो लंबित लेनदेन में बंद हैं और जिन्हें आपने अपनी सिक्का नियंत्रण सेटिंग्स में सक्रिय रूप से जमा कर रखा है। लॉक किए गए शेष उनके संबंधित लेन-देन पूरे होने के बाद उपलब्ध हो जाएंगे, जबकि जमे हुए शेष लेन-देन के लिए अप्राप्य रहेंगे जब तक कि आप उन्हें अनफ्रीज करने का निर्णय नहीं लेते।", "unspent_change": "परिवर्तन", "tor_connection": "टोर कनेक्शन", - "seed_hex_form": "वॉलेट सीड (हेक्स फॉर्म)" + "seed_hex_form": "वॉलेट सीड (हेक्स फॉर्म)", + "seedtype": "बीज", + "seedtype_legacy": "विरासत (25 शब्द)", + "seedtype_polyseed": "पॉलीसीड (16 शब्द)", + "seed_language_czech": "चेक", + "seed_language_korean": "कोरियाई", + "seed_language_chinese_traditional": "चीनी पारंपरिक)" } \ No newline at end of file diff --git a/res/values/strings_hr.arb b/res/values/strings_hr.arb index 4e84d3ed4..3c0f895e7 100644 --- a/res/values/strings_hr.arb +++ b/res/values/strings_hr.arb @@ -741,5 +741,11 @@ "unavailable_balance_description": "Nedostupno stanje: Ovaj ukupni iznos uključuje sredstva koja su zaključana u transakcijama na čekanju i ona koja ste aktivno zamrznuli u postavkama kontrole novčića. Zaključani saldi postat će dostupni kada se dovrše njihove transakcije, dok zamrznuti saldi ostaju nedostupni za transakcije sve dok ih ne odlučite odmrznuti.", "unspent_change": "Promijeniti", "tor_connection": "Tor veza", - "seed_hex_form": "Sjeme novčanika (šesterokutni oblik)" + "seed_hex_form": "Sjeme novčanika (šesterokutni oblik)", + "seedtype": "Sjemenska vrsta", + "seedtype_legacy": "Nasljeđe (25 riječi)", + "seedtype_polyseed": "Poliseed (16 riječi)", + "seed_language_czech": "češki", + "seed_language_korean": "korejski", + "seed_language_chinese_traditional": "Kinesko tradicionalno)" } \ No newline at end of file diff --git a/res/values/strings_id.arb b/res/values/strings_id.arb index 82e9bca56..b29572746 100644 --- a/res/values/strings_id.arb +++ b/res/values/strings_id.arb @@ -731,5 +731,11 @@ "unavailable_balance_description": "Saldo Tidak Tersedia: Total ini termasuk dana yang terkunci dalam transaksi yang tertunda dan dana yang telah Anda bekukan secara aktif di pengaturan kontrol koin Anda. Saldo yang terkunci akan tersedia setelah transaksi masing-masing selesai, sedangkan saldo yang dibekukan tetap tidak dapat diakses untuk transaksi sampai Anda memutuskan untuk mencairkannya.", "unspent_change": "Mengubah", "tor_connection": "koneksi Tor", - "seed_hex_form": "Biji dompet (bentuk hex)" + "seed_hex_form": "Biji dompet (bentuk hex)", + "seedtype": "Seedtype", + "seedtype_legacy": "Legacy (25 kata)", + "seedtype_polyseed": "Polyseed (16 kata)", + "seed_language_czech": "Ceko", + "seed_language_korean": "Korea", + "seed_language_chinese_traditional": "Cina tradisional)" } \ No newline at end of file diff --git a/res/values/strings_it.arb b/res/values/strings_it.arb index 0005fb5e7..19912d277 100644 --- a/res/values/strings_it.arb +++ b/res/values/strings_it.arb @@ -743,5 +743,11 @@ "unavailable_balance_description": "Saldo non disponibile: questo totale include i fondi bloccati nelle transazioni in sospeso e quelli che hai congelato attivamente nelle impostazioni di controllo delle monete. I saldi bloccati diventeranno disponibili una volta completate le rispettive transazioni, mentre i saldi congelati rimarranno inaccessibili per le transazioni finché non deciderai di sbloccarli.", "unspent_change": "Modifica", "tor_connection": "Connessione Tor", - "seed_hex_form": "Seme di portafoglio (forma esadecimale)" + "seed_hex_form": "Seme di portafoglio (forma esadecimale)", + "seedtype": "Seedtype", + "seedtype_legacy": "Legacy (25 parole)", + "seedtype_polyseed": "Polyseed (16 parole)", + "seed_language_czech": "ceco", + "seed_language_korean": "coreano", + "seed_language_chinese_traditional": "Cinese tradizionale)" } \ No newline at end of file diff --git a/res/values/strings_ja.arb b/res/values/strings_ja.arb index d57eaef5d..ea138b317 100644 --- a/res/values/strings_ja.arb +++ b/res/values/strings_ja.arb @@ -743,5 +743,11 @@ "unavailable_balance_description": "利用不可能な残高: この合計には、保留中のトランザクションにロックされている資金と、コイン管理設定でアクティブに凍結した資金が含まれます。ロックされた残高は、それぞれの取引が完了すると利用可能になりますが、凍結された残高は、凍結を解除するまで取引にアクセスできません。", "unspent_change": "変化", "tor_connection": "Tor接続", - "seed_hex_form": "ウォレットシード(ヘックスフォーム)" + "seed_hex_form": "ウォレットシード(ヘックスフォーム)", + "seedtype": "SeedType", + "seedtype_legacy": "レガシー(25語)", + "seedtype_polyseed": "ポリシード(16語)", + "seed_language_czech": "チェコ", + "seed_language_korean": "韓国語", + "seed_language_chinese_traditional": "中国の伝統的な)" } \ No newline at end of file diff --git a/res/values/strings_ko.arb b/res/values/strings_ko.arb index 775918659..4df43018d 100644 --- a/res/values/strings_ko.arb +++ b/res/values/strings_ko.arb @@ -741,5 +741,11 @@ "unavailable_balance_description": "사용할 수 없는 잔액: 이 총계에는 보류 중인 거래에 잠겨 있는 자금과 코인 관리 설정에서 적극적으로 동결된 자금이 포함됩니다. 잠긴 잔액은 해당 거래가 완료되면 사용할 수 있게 되며, 동결된 잔액은 동결을 해제하기 전까지 거래에 액세스할 수 없습니다.", "unspent_change": "변화", "tor_connection": "토르 연결", - "seed_hex_form": "지갑 씨앗 (16 진 양식)" + "seed_hex_form": "지갑 씨앗 (16 진 양식)", + "seedtype": "시드 타입", + "seedtype_legacy": "레거시 (25 단어)", + "seedtype_polyseed": "다문 (16 단어)", + "seed_language_czech": "체코 사람", + "seed_language_korean": "한국인", + "seed_language_chinese_traditional": "중국 전통)" } \ No newline at end of file diff --git a/res/values/strings_my.arb b/res/values/strings_my.arb index 4aacb0bd3..d82e30116 100644 --- a/res/values/strings_my.arb +++ b/res/values/strings_my.arb @@ -741,5 +741,11 @@ "unavailable_balance_description": "မရရှိနိုင်သော လက်ကျန်ငွေ- ဤစုစုပေါင်းတွင် ဆိုင်းငံ့ထားသော ငွေပေးငွေယူများတွင် သော့ခတ်ထားသော ငွေကြေးများနှင့် သင်၏ coin ထိန်းချုပ်မှုဆက်တင်များတွင် သင် တက်ကြွစွာ အေးခဲထားသော ငွေများ ပါဝင်သည်။ သော့ခတ်ထားသော လက်ကျန်ငွေများကို ၎င်းတို့၏ သက်ဆိုင်ရာ ငွေပေးငွေယူများ ပြီးမြောက်သည်နှင့် တပြိုင်နက် ရရှိနိုင်မည်ဖြစ်ပြီး၊ အေးခဲထားသော လက်ကျန်များကို ၎င်းတို့အား ပြန်ဖြုတ်ရန် သင်ဆုံးဖြတ်သည်အထိ ငွေပေးငွေယူများအတွက် ဆက်လက်၍မရနိုင်ပါ။", "unspent_change": "ပေြာင်းလဲခြင်း", "tor_connection": "Tor ချိတ်ဆက်မှု", - "seed_hex_form": "ပိုက်ဆံအိတ်မျိုးစေ့ (Hex Form)" + "seed_hex_form": "ပိုက်ဆံအိတ်မျိုးစေ့ (Hex Form)", + "seedtype": "မျိုးပွားခြင်း", + "seedtype_legacy": "အမွေအနှစ် (စကားလုံး 25 လုံး)", + "seedtype_polyseed": "polyseed (စကားလုံး 16 လုံး)", + "seed_language_czech": "ချက်", + "seed_language_korean": "ကိုးရီးယား", + "seed_language_chinese_traditional": "တရုတ်ရိုးရာ)" } \ No newline at end of file diff --git a/res/values/strings_nl.arb b/res/values/strings_nl.arb index cf779afab..8a290618d 100644 --- a/res/values/strings_nl.arb +++ b/res/values/strings_nl.arb @@ -743,5 +743,11 @@ "unavailable_balance_description": "Niet-beschikbaar saldo: Dit totaal omvat het geld dat is vergrendeld in lopende transacties en het geld dat u actief hebt bevroren in uw muntcontrole-instellingen. Vergrendelde saldi komen beschikbaar zodra de betreffende transacties zijn voltooid, terwijl bevroren saldi ontoegankelijk blijven voor transacties totdat u besluit ze weer vrij te geven.", "unspent_change": "Wijziging", "tor_connection": "Tor-verbinding", - "seed_hex_form": "Portemonnee zaad (hexvorm)" + "seed_hex_form": "Portemonnee zaad (hexvorm)", + "seedtype": "Zaadtype", + "seedtype_legacy": "Legacy (25 woorden)", + "seedtype_polyseed": "Polyseed (16 woorden)", + "seed_language_czech": "Tsjechisch", + "seed_language_korean": "Koreaans", + "seed_language_chinese_traditional": "Chinese traditionele)" } \ No newline at end of file diff --git a/res/values/strings_pl.arb b/res/values/strings_pl.arb index 04c420db4..b84ddc98c 100644 --- a/res/values/strings_pl.arb +++ b/res/values/strings_pl.arb @@ -743,5 +743,11 @@ "unavailable_balance_description": "Niedostępne saldo: Suma ta obejmuje środki zablokowane w transakcjach oczekujących oraz te, które aktywnie zamroziłeś w ustawieniach kontroli monet. Zablokowane salda staną się dostępne po zakończeniu odpowiednich transakcji, natomiast zamrożone salda pozostaną niedostępne dla transakcji, dopóki nie zdecydujesz się ich odblokować.", "unspent_change": "Zmiana", "tor_connection": "Połączenie Torem", - "seed_hex_form": "Nasiona portfela (forma sześciokątna)" + "seed_hex_form": "Nasiona portfela (forma sześciokątna)", + "seedtype": "Sedtype", + "seedtype_legacy": "Dziedzictwo (25 słów)", + "seedtype_polyseed": "Poliqueed (16 słów)", + "seed_language_czech": "Czech", + "seed_language_korean": "koreański", + "seed_language_chinese_traditional": "Chiński tradycyjny)" } \ No newline at end of file diff --git a/res/values/strings_pt.arb b/res/values/strings_pt.arb index a461141f3..ed7b8a801 100644 --- a/res/values/strings_pt.arb +++ b/res/values/strings_pt.arb @@ -742,5 +742,11 @@ "unavailable_balance_description": "Saldo Indisponível: Este total inclui fundos bloqueados em transações pendentes e aqueles que você congelou ativamente nas configurações de controle de moedas. Os saldos bloqueados ficarão disponíveis assim que suas respectivas transações forem concluídas, enquanto os saldos congelados permanecerão inacessíveis para transações até que você decida descongelá-los.", "unspent_change": "Mudar", "tor_connection": "Conexão Tor", - "seed_hex_form": "Semente de carteira (forma hexadecimal)" + "seed_hex_form": "Semente de carteira (forma hexadecimal)", + "seedtype": "SeedType", + "seedtype_legacy": "Legado (25 palavras)", + "seedtype_polyseed": "Polyseed (16 palavras)", + "seed_language_czech": "Tcheco", + "seed_language_korean": "coreano", + "seed_language_chinese_traditional": "Chinês tradicional)" } \ No newline at end of file diff --git a/res/values/strings_ru.arb b/res/values/strings_ru.arb index 8d0cc647a..c7749d0ea 100644 --- a/res/values/strings_ru.arb +++ b/res/values/strings_ru.arb @@ -743,5 +743,11 @@ "unavailable_balance_description": "Недоступный баланс: в эту сумму входят средства, заблокированные в ожидающих транзакциях, и средства, которые вы активно заморозили в настройках управления монетами. Заблокированные балансы станут доступны после завершения соответствующих транзакций, а замороженные балансы останутся недоступными для транзакций, пока вы не решите их разморозить.", "unspent_change": "Изменять", "tor_connection": "Тор соединение", - "seed_hex_form": "Семя кошелька (шестнадцатеричная форма)" + "seed_hex_form": "Семя кошелька (шестнадцатеричная форма)", + "seedtype": "SEEDTYPE", + "seedtype_legacy": "Наследие (25 слов)", + "seedtype_polyseed": "Полиса (16 слов)", + "seed_language_czech": "Чешский", + "seed_language_korean": "Корейский", + "seed_language_chinese_traditional": "Китайский традиционный)" } \ No newline at end of file diff --git a/res/values/strings_th.arb b/res/values/strings_th.arb index 151c65cd3..791b0f005 100644 --- a/res/values/strings_th.arb +++ b/res/values/strings_th.arb @@ -741,5 +741,11 @@ "unavailable_balance_description": "ยอดคงเหลือที่ไม่พร้อมใช้งาน: ยอดรวมนี้รวมถึงเงินทุนที่ถูกล็อคในการทำธุรกรรมที่รอดำเนินการและที่คุณได้แช่แข็งไว้ในการตั้งค่าการควบคุมเหรียญของคุณ ยอดคงเหลือที่ถูกล็อคจะพร้อมใช้งานเมื่อธุรกรรมที่เกี่ยวข้องเสร็จสมบูรณ์ ในขณะที่ยอดคงเหลือที่แช่แข็งจะไม่สามารถเข้าถึงได้สำหรับธุรกรรมจนกว่าคุณจะตัดสินใจยกเลิกการแช่แข็ง", "unspent_change": "เปลี่ยน", "tor_connection": "การเชื่อมต่อทอร์", - "seed_hex_form": "เมล็ดกระเป๋าเงิน (รูปแบบฐานสิบหก)" + "seed_hex_form": "เมล็ดกระเป๋าเงิน (รูปแบบฐานสิบหก)", + "seedtype": "เมล็ดพันธุ์", + "seedtype_legacy": "มรดก (25 คำ)", + "seedtype_polyseed": "โพลีส (16 คำ)", + "seed_language_czech": "ภาษาเช็ก", + "seed_language_korean": "เกาหลี", + "seed_language_chinese_traditional": "จีน (ดั้งเดิม)" } \ No newline at end of file diff --git a/res/values/strings_tl.arb b/res/values/strings_tl.arb index 258eb6f12..8891563b0 100644 --- a/res/values/strings_tl.arb +++ b/res/values/strings_tl.arb @@ -738,5 +738,10 @@ "unavailable_balance_description": "Hindi Available na Balanse: Kasama sa kabuuang ito ang mga pondong naka-lock sa mga nakabinbing transaksyon at ang mga aktibong na-freeze mo sa iyong mga setting ng kontrol ng coin. Magiging available ang mga naka-lock na balanse kapag nakumpleto na ang kani-kanilang mga transaksyon, habang ang mga nakapirming balanse ay nananatiling hindi naa-access para sa mga transaksyon hanggang sa magpasya kang i-unfreeze ang mga ito.", "unspent_change": "Baguhin", "tor_connection": "Koneksyon ng Tor", - "seed_hex_form": "Wallet seed (hex form)" + "seed_hex_form": "Wallet seed (hex form)", + "seedtype_legacy": "Pamana (25 salita)", + "seedtype_polyseed": "Polyseed (16 na salita)", + "seed_language_czech": "Czech", + "seed_language_korean": "Korean", + "seed_language_chinese_traditional": "Intsik (tradisyonal)" } \ No newline at end of file diff --git a/res/values/strings_tr.arb b/res/values/strings_tr.arb index 33362b83c..a5d6a330a 100644 --- a/res/values/strings_tr.arb +++ b/res/values/strings_tr.arb @@ -741,5 +741,11 @@ "unavailable_balance_description": "Kullanılamayan Bakiye: Bu toplam, bekleyen işlemlerde kilitlenen fonları ve jeton kontrol ayarlarınızda aktif olarak dondurduğunuz fonları içerir. Kilitli bakiyeler, ilgili işlemleri tamamlandıktan sonra kullanılabilir hale gelir; dondurulmuş bakiyeler ise siz onları dondurmaya karar verene kadar işlemler için erişilemez durumda kalır.", "unspent_change": "Değiştirmek", "tor_connection": "Tor bağlantısı", - "seed_hex_form": "Cüzdan tohumu (onaltılık form)" + "seed_hex_form": "Cüzdan tohumu (onaltılık form)", + "seedtype": "Tohum", + "seedtype_legacy": "Miras (25 kelime)", + "seedtype_polyseed": "Polyseed (16 kelime)", + "seed_language_czech": "Çek", + "seed_language_korean": "Koreli", + "seed_language_chinese_traditional": "Çin geleneği)" } \ No newline at end of file diff --git a/res/values/strings_uk.arb b/res/values/strings_uk.arb index 7b79ac6e4..81bc3c8aa 100644 --- a/res/values/strings_uk.arb +++ b/res/values/strings_uk.arb @@ -743,5 +743,11 @@ "unavailable_balance_description": "Недоступний баланс: ця сума включає кошти, заблоковані в незавершених транзакціях, і ті, які ви активно заморозили в налаштуваннях контролю монет. Заблоковані баланси стануть доступними після завершення відповідних транзакцій, тоді як заморожені баланси залишаються недоступними для транзакцій, доки ви не вирішите їх розморозити.", "unspent_change": "Зміна", "tor_connection": "Підключення Tor", - "seed_hex_form": "Насіння гаманця (шістнадцяткова форма)" + "seed_hex_form": "Насіння гаманця (шістнадцяткова форма)", + "seedtype": "Насіннєвий тип", + "seedtype_legacy": "Спадщина (25 слів)", + "seedtype_polyseed": "Полісей (16 слів)", + "seed_language_czech": "Чеський", + "seed_language_korean": "Корейський", + "seed_language_chinese_traditional": "Китайський традиційний)" } \ No newline at end of file diff --git a/res/values/strings_ur.arb b/res/values/strings_ur.arb index c8362ab33..5b7f18ae7 100644 --- a/res/values/strings_ur.arb +++ b/res/values/strings_ur.arb @@ -735,5 +735,11 @@ "unavailable_balance_description": "۔ﮯﺗﺮﮐ ﮟﯿﮩﻧ ﮧﻠﺼﯿﻓ ﺎﮐ ﮯﻧﺮﮐ ﺪﻤﺠﻨﻣ ﻥﺍ ﮟﯿﮩﻧﺍ ﭖﺁ ﮧﮐ ﮏﺗ ﺐﺟ ﮟﯿﮨ ﮯﺘﮨﺭ ﯽﺋﺎﺳﺭ ﻞﺑﺎﻗﺎﻧ ﮏﺗ ﺖﻗﻭ ﺱﺍ ﮯﯿﻟ ﮯﮐ ﻦﯾﺩ ﻦﯿﻟ ﺲﻨﻠﯿﺑ ﺪﻤﺠﻨﻣ ﮧﮐ ﺐﺟ ،ﮯﮔ ﮟﯿﺋﺎﺟ ﻮﮨ ﺏﺎﯿﺘﺳﺩ ﺲﻨﻠﯿﺑ ﻞﻔﻘﻣ ﺪﻌﺑ ﮯﮐ ﮯﻧﻮﮨ ﻞﻤﮑﻣ ﻦﯾﺩ ﻦﯿﻟ ﮧﻘﻠﻌﺘﻣ ﮯﮐ ﻥﺍ ۔ﮯﮨ ﺎﮭﮐﺭ ﺮ", "unspent_change": "تبدیل کریں", "seed_hex_form": "پرس بیج (ہیکس فارم)", - "tor_connection": "ﻦﺸﮑﻨﮐ ﺭﻮﭨ" + "tor_connection": "ﻦﺸﮑﻨﮐ ﺭﻮﭨ", + "seedtype": "سیڈ ٹائپ", + "seedtype_legacy": "میراث (25 الفاظ)", + "seedtype_polyseed": "پالیسیڈ (16 الفاظ)", + "seed_language_czech": "چیک", + "seed_language_korean": "کورین", + "seed_language_chinese_traditional": "چینی (روایتی)" } \ No newline at end of file diff --git a/res/values/strings_yo.arb b/res/values/strings_yo.arb index 7b9b075d7..6821aa7f9 100644 --- a/res/values/strings_yo.arb +++ b/res/values/strings_yo.arb @@ -737,5 +737,11 @@ "unavailable_balance_description": "Iwontunws.funfun ti ko si: Lapapọ yii pẹlu awọn owo ti o wa ni titiipa ni awọn iṣowo isunmọ ati awọn ti o ti didi ni itara ninu awọn eto iṣakoso owo rẹ. Awọn iwọntunwọnsi titiipa yoo wa ni kete ti awọn iṣowo oniwun wọn ba ti pari, lakoko ti awọn iwọntunwọnsi tio tutunini ko ni iraye si fun awọn iṣowo titi iwọ o fi pinnu lati mu wọn kuro.", "unspent_change": "Yipada", "tor_connection": "Tor asopọ", - "seed_hex_form": "Irú Opamọwọ apamọwọ (HOX)" + "seed_hex_form": "Irú Opamọwọ apamọwọ (HOX)", + "seedtype": "Irugbin-seetypu", + "seedtype_legacy": "Legacy (awọn ọrọ 25)", + "seedtype_polyseed": "Polyseed (awọn ọrọ 16)", + "seed_language_czech": "Czech", + "seed_language_korean": "Ara ẹni", + "seed_language_chinese_traditional": "Kannada (ibile)" } \ No newline at end of file diff --git a/res/values/strings_zh.arb b/res/values/strings_zh.arb index e95bc077b..b66d0e65e 100644 --- a/res/values/strings_zh.arb +++ b/res/values/strings_zh.arb @@ -742,5 +742,11 @@ "unavailable_balance_description": "不可用余额:此总额包括锁定在待处理交易中的资金以及您在硬币控制设置中主动冻结的资金。一旦各自的交易完成,锁定的余额将变得可用,而冻结的余额在您决定解冻之前仍然无法进行交易。", "unspent_change": "改变", "tor_connection": "Tor连接", - "seed_hex_form": "钱包种子(十六进制形式)" + "seed_hex_form": "钱包种子(十六进制形式)", + "seedtype": "籽粒", + "seedtype_legacy": "遗产(25个单词)", + "seedtype_polyseed": "多种物品(16个单词)", + "seed_language_czech": "捷克", + "seed_language_korean": "韩国人", + "seed_language_chinese_traditional": "中国传统的)" } \ No newline at end of file diff --git a/tool/configure.dart b/tool/configure.dart index bc32581a6..7d50ddf53 100644 --- a/tool/configure.dart +++ b/tool/configure.dart @@ -134,7 +134,6 @@ import 'package:cw_core/unspent_transaction_output.dart'; import 'package:cw_core/unspent_coins_info.dart'; import 'package:cw_monero/monero_unspent.dart'; import 'package:mobx/mobx.dart'; -import 'package:flutter/foundation.dart'; import 'package:cw_core/wallet_credentials.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/transaction_priority.dart'; @@ -144,7 +143,8 @@ import 'package:cw_core/balance.dart'; import 'package:cw_core/output_info.dart'; import 'package:cake_wallet/view_model/send/output.dart'; import 'package:cw_core/wallet_service.dart'; -import 'package:hive/hive.dart';"""; +import 'package:hive/hive.dart'; +import 'package:polyseed/polyseed.dart';"""; const moneroCWHeaders = """ import 'package:cw_core/get_height_by_date.dart'; import 'package:cw_core/monero_amount_format.dart'; @@ -152,7 +152,6 @@ import 'package:cw_core/monero_transaction_priority.dart'; import 'package:cw_monero/monero_wallet_service.dart'; import 'package:cw_monero/monero_wallet.dart'; import 'package:cw_monero/monero_transaction_info.dart'; -import 'package:cw_monero/monero_transaction_history.dart'; import 'package:cw_monero/monero_transaction_creation_credentials.dart'; import 'package:cw_core/account.dart' as monero_account; import 'package:cw_monero/api/wallet.dart' as monero_wallet_api; @@ -255,7 +254,7 @@ abstract class Monero { required String language, required int height}); WalletCredentials createMoneroRestoreWalletFromSeedCredentials({required String name, required String password, required int height, required String mnemonic}); - WalletCredentials createMoneroNewWalletCredentials({required String name, required String language, String password,}); + WalletCredentials createMoneroNewWalletCredentials({required String name, required String language, required bool isPolyseed, String password}); Map getKeys(Object wallet); Object createMoneroTransactionCreationCredentials({required List outputs, required TransactionPriority priority}); Object createMoneroTransactionCreationCredentialsRaw({required List outputs, required TransactionPriority priority});