CW-723-Add-Monero-support-to-the-Shared-Seed-feature-in-Cake (#2131)

* feat: add exodus style bip39 to monero legacy seed

* feat: restore monero wallet from bip39 and add test

* bug: fix wrong naming in CI

* feat: add monero bip39 UI flow

* fix: monero.dart generation

* fix: skip monero_wallet_service tests till CI is fixed

* ci: copy monero_libwallet2_api_c.so to /usr/lib for testing
ci: reduce timeout for cw_monero tests

* fix: monero wallet creation credentials default to bip39 if mnemonic are set

* fix: do not skip monero wallets services test

* fix: Include non bip39 monero wallets on Wallet Group

* fix: null pointer stemming from missing language selector if seed is selected

* fix: Fixes to Bip39 Creation and restore

- Do not restore from 0 for fresh bip39 wallet
- disallow restoring bip39 wallet without date or height

* fix: Fixes to Bip39 restore

- Refresh height is now getting set correctly
- Add new create monero wallet tests
- Add seed-language English for Bip39 Monero wallets
- Fix seed-type naming

* feat (cw_monero): Store monero wallet after bip39 creation

* feat (cw_monero): remove prints from monero_wallet_service_test.dart

* fix: exception during seed language autodetect

* feat (cw_monero): Add support for passphrases on bip39 seeds

* feat (cw_monero): Add support for passphrases on bip39 seeds

* fix: seed language selection for recovering bip39 wallets

* style: improve readability of isLegacySeedOnly in wallet_keys_view_model.dart

* feat: hide monero seed type selector from advanced settings when creating a child wallet

* fix(cw_monero): use named arguments for bip39_seed tests

---------

Co-authored-by: cyan <cyjan@mrcyjanek.net>
This commit is contained in:
Konstantin Ullrich 2025-04-10 03:31:26 +02:00 committed by GitHub
parent 494207290e
commit f58a5fb8fd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
51 changed files with 702 additions and 283 deletions

View file

@ -283,6 +283,9 @@ jobs:
xmessage -timeout 30 "restore_wallet_through_seeds_flow_test" & xmessage -timeout 30 "restore_wallet_through_seeds_flow_test" &
rm -rf ~/.local/share/com.example.cake_wallet/ ~/Documents/cake_wallet/ ~/cake_wallet rm -rf ~/.local/share/com.example.cake_wallet/ ~/Documents/cake_wallet/ ~/cake_wallet
exec timeout --signal=SIGKILL 900 flutter drive --driver=test_driver/integration_test.dart --target=integration_test/test_suites/restore_wallet_through_seeds_flow_test.dart exec timeout --signal=SIGKILL 900 flutter drive --driver=test_driver/integration_test.dart --target=integration_test/test_suites/restore_wallet_through_seeds_flow_test.dart
- name: Test [cw_monero]
timeout-minutes: 2
run: cd cw_monero && flutter test
- name: Stop screen recording, encrypt and upload - name: Stop screen recording, encrypt and upload
if: always() if: always()
run: | run: |

View file

@ -12,3 +12,4 @@ android/.cxx/
macos/cw_monero.podspec macos/cw_monero.podspec
macos/External/ macos/External/
*monero_libwallet2_api_c.*

View file

@ -62,6 +62,11 @@ String getSeed() {
} }
return cakepolyseed; return cakepolyseed;
} }
final bip39 = monero.Wallet_getCacheAttribute(wptr!, key: "cakewallet.seed.bip39");
if(bip39.isNotEmpty) return bip39;
final legacy = getSeedLegacy(null); final legacy = getSeedLegacy(null);
return legacy; return legacy;
} }

View file

@ -0,0 +1,59 @@
import 'dart:typed_data';
import 'package:bip32/bip32.dart' as bip32;
import 'package:bip39/bip39.dart' as bip39;
import 'package:polyseed/polyseed.dart';
bool isBip39Seed(String mnemonic) => bip39.validateMnemonic(mnemonic);
String getBip39Seed() => bip39.generateMnemonic();
String getLegacySeedFromBip39(String mnemonic,
{int accountIndex = 0, String passphrase = ""}) {
final seed = bip39.mnemonicToSeed(mnemonic, passphrase: passphrase);
final bip32KeyPair =
bip32.BIP32.fromSeed(seed).derivePath("m/44'/128'/$accountIndex'/0/0");
final spendKey = _reduceECKey(bip32KeyPair.privateKey!);
return LegacySeedLang.getByEnglishName("English")
.encodePhrase(spendKey.toHexString());
}
const _ed25519CurveOrder =
"1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED";
Uint8List _reduceECKey(Uint8List buffer) {
final curveOrder = BigInt.parse(_ed25519CurveOrder, radix: 16);
final bigNumber = _readBytes(buffer);
var result = bigNumber % curveOrder;
final resultBuffer = Uint8List(32);
for (var i = 0; i < 32; i++) {
resultBuffer[i] = (result & BigInt.from(0xff)).toInt();
result = result >> 8;
}
return resultBuffer;
}
/// Read BigInt from a little-endian Uint8List
/// From https://github.com/dart-lang/sdk/issues/32803#issuecomment-387405784
BigInt _readBytes(Uint8List bytes) {
BigInt read(int start, int end) {
if (end - start <= 4) {
var result = 0;
for (int i = end - 1; i >= start; i--) {
result = result * 256 + bytes[i];
}
return BigInt.from(result);
}
final mid = start + ((end - start) >> 1);
return read(start, mid) +
read(mid, end) * (BigInt.one << ((mid - start) * 8));
}
return read(0, bytes.length);
}

View file

@ -1,6 +1,7 @@
import 'dart:ffi'; import 'dart:ffi';
import 'dart:io'; import 'dart:io';
import 'package:collection/collection.dart';
import 'package:cw_core/get_height_by_date.dart'; import 'package:cw_core/get_height_by_date.dart';
import 'package:cw_core/monero_wallet_utils.dart'; import 'package:cw_core/monero_wallet_utils.dart';
import 'package:cw_core/pathForWallet.dart'; import 'package:cw_core/pathForWallet.dart';
@ -14,26 +15,35 @@ import 'package:cw_core/wallet_type.dart';
import 'package:cw_monero/api/account_list.dart'; import 'package:cw_monero/api/account_list.dart';
import 'package:cw_monero/api/wallet_manager.dart' as monero_wallet_manager; import 'package:cw_monero/api/wallet_manager.dart' as monero_wallet_manager;
import 'package:cw_monero/api/wallet_manager.dart'; import 'package:cw_monero/api/wallet_manager.dart';
import 'package:cw_monero/bip39_seed.dart';
import 'package:cw_monero/ledger.dart'; import 'package:cw_monero/ledger.dart';
import 'package:cw_monero/monero_wallet.dart'; import 'package:cw_monero/monero_wallet.dart';
import 'package:collection/collection.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart'; import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';
import 'package:monero/monero.dart' as monero; import 'package:monero/monero.dart' as monero;
import 'package:polyseed/polyseed.dart'; import 'package:polyseed/polyseed.dart';
enum MoneroSeedType { polyseed, legacy, bip39 }
class MoneroNewWalletCredentials extends WalletCredentials { class MoneroNewWalletCredentials extends WalletCredentials {
MoneroNewWalletCredentials( MoneroNewWalletCredentials(
{required String name, required this.language, required this.isPolyseed, String? password, this.passphrase}) {required String name,
required this.language,
required this.seedType,
String? password,
this.passphrase,
this.mnemonic})
: super(name: name, password: password); : super(name: name, password: password);
final String language; final String language;
final bool isPolyseed; final MoneroSeedType seedType;
final String? passphrase; final String? passphrase;
final String? mnemonic;
} }
class MoneroRestoreWalletFromHardwareCredentials extends WalletCredentials { class MoneroRestoreWalletFromHardwareCredentials extends WalletCredentials {
MoneroRestoreWalletFromHardwareCredentials({required String name, MoneroRestoreWalletFromHardwareCredentials(
{required String name,
required this.ledgerConnection, required this.ledgerConnection,
int height = 0, int height = 0,
String? password}) String? password})
@ -60,7 +70,8 @@ class MoneroWalletLoadingException implements Exception {
} }
class MoneroRestoreWalletFromKeysCredentials extends WalletCredentials { class MoneroRestoreWalletFromKeysCredentials extends WalletCredentials {
MoneroRestoreWalletFromKeysCredentials({required String name, MoneroRestoreWalletFromKeysCredentials(
{required String name,
required String password, required String password,
required this.language, required this.language,
required this.address, required this.address,
@ -98,26 +109,41 @@ class MoneroWalletService extends WalletService<
WalletType getType() => WalletType.monero; WalletType getType() => WalletType.monero;
@override @override
Future<MoneroWallet> create(MoneroNewWalletCredentials credentials, {bool? isTestnet}) async { Future<MoneroWallet> create(MoneroNewWalletCredentials credentials,
{bool? isTestnet}) async {
try { try {
final path = await pathForWallet(name: credentials.name, type: getType()); final path = await pathForWallet(name: credentials.name, type: getType());
if (credentials.isPolyseed) { if (credentials.seedType == MoneroSeedType.bip39) {
return _restoreFromBip39(
path: path,
password: credentials.password!,
mnemonic: credentials.mnemonic ?? getBip39Seed(),
passphrase: credentials.passphrase,
walletInfo: credentials.walletInfo!,
);
}
if (credentials.seedType == MoneroSeedType.polyseed) {
final polyseed = Polyseed.create(); final polyseed = Polyseed.create();
final lang = PolyseedLang.getByEnglishName(credentials.language); final lang = PolyseedLang.getByEnglishName(credentials.language);
if (credentials.passphrase != null) polyseed.crypt(credentials.passphrase!); if (credentials.passphrase != null)
polyseed.crypt(credentials.passphrase!);
final heightOverride = final heightOverride = getMoneroHeigthByDate(
getMoneroHeigthByDate(date: DateTime.now().subtract(Duration(days: 2))); date: DateTime.now().subtract(Duration(days: 2)));
return _restoreFromPolyseed( return _restoreFromPolyseed(path, credentials.password!, polyseed,
path, credentials.password!, polyseed, credentials.walletInfo!, lang, credentials.walletInfo!, lang,
overrideHeight: heightOverride, passphrase: credentials.passphrase); overrideHeight: heightOverride, passphrase: credentials.passphrase);
} }
await monero_wallet_manager.createWallet( await monero_wallet_manager.createWallet(
path: path, password: credentials.password!, language: credentials.language, passphrase: credentials.passphrase??""); path: path,
password: credentials.password!,
language: credentials.language,
passphrase: credentials.passphrase ?? "");
final wallet = MoneroWallet( final wallet = MoneroWallet(
walletInfo: credentials.walletInfo!, walletInfo: credentials.walletInfo!,
unspentCoinsInfo: unspentCoinsInfoSource, unspentCoinsInfo: unspentCoinsInfoSource,
@ -145,7 +171,8 @@ class MoneroWalletService extends WalletService<
} }
@override @override
Future<MoneroWallet> openWallet(String name, String password, {OpenWalletTry openWalletTry = OpenWalletTry.initial}) async { Future<MoneroWallet> openWallet(String name, String password,
{OpenWalletTry openWalletTry = OpenWalletTry.initial}) async {
try { try {
final path = await pathForWallet(name: name, type: getType()); final path = await pathForWallet(name: name, type: getType());
@ -303,8 +330,28 @@ class MoneroWalletService extends WalletService<
rethrow; rethrow;
} }
try {
if (isBip39Seed(credentials.mnemonic)) {
final path =
await pathForWallet(name: credentials.name, type: getType());
return _restoreFromBip39(
path: path,
password: credentials.password!,
mnemonic: credentials.mnemonic,
walletInfo: credentials.walletInfo!,
overrideHeight: credentials.height!,
passphrase: credentials.passphrase,
);
}
} catch (e) {
printV("Bip39 restore failed: $e");
rethrow;
}
try { try {
final path = await pathForWallet(name: credentials.name, type: getType()); final path = await pathForWallet(name: credentials.name, type: getType());
monero_wallet_manager.restoreFromSeed( monero_wallet_manager.restoreFromSeed(
path: path, path: path,
password: credentials.password!, password: credentials.password!,
@ -325,6 +372,50 @@ class MoneroWalletService extends WalletService<
} }
} }
Future<MoneroWallet> _restoreFromBip39({
required String path,
required String password,
required String mnemonic,
required WalletInfo walletInfo,
String? passphrase,
int? overrideHeight,
}) async {
walletInfo.derivationInfo = DerivationInfo(
derivationType: DerivationType.bip39,
derivationPath: "m/44'/128'/0'/0/0",
);
final legacyMnemonic =
getLegacySeedFromBip39(mnemonic, passphrase: passphrase ?? "");
final height =
overrideHeight ?? getMoneroHeigthByDate(date: DateTime.now());
walletInfo.isRecovery = true;
walletInfo.restoreHeight = height;
monero_wallet_manager.restoreFromSeed(
path: path,
password: password,
passphrase: '',
seed: legacyMnemonic,
restoreHeight: height,
);
monero.Wallet_setCacheAttribute(wptr!,
key: "cakewallet.seed.bip39", value: mnemonic);
monero.Wallet_store(wptr!);
final wallet = MoneroWallet(
walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfoSource,
password: password,
);
await wallet.init();
return wallet;
}
Future<MoneroWallet> restoreFromPolyseed( Future<MoneroWallet> restoreFromPolyseed(
MoneroRestoreWalletFromSeedCredentials credentials) async { MoneroRestoreWalletFromSeedCredentials credentials) async {
try { try {
@ -344,21 +435,19 @@ class MoneroWalletService extends WalletService<
} }
} }
Future<MoneroWallet> _restoreFromPolyseed( Future<MoneroWallet> _restoreFromPolyseed(String path, String password,
String path, String password, Polyseed polyseed, WalletInfo walletInfo, PolyseedLang lang, Polyseed polyseed, WalletInfo walletInfo, PolyseedLang lang,
{PolyseedCoin coin = PolyseedCoin.POLYSEED_MONERO, {PolyseedCoin coin = PolyseedCoin.POLYSEED_MONERO,
int? overrideHeight, int? overrideHeight,
String? passphrase}) async { String? passphrase}) async {
if (polyseed.isEncrypted == false && (passphrase ?? '') != "") {
if (polyseed.isEncrypted == false &&
(passphrase??'') != "") {
// Fallback to the different passphrase offset method, when a passphrase // Fallback to the different passphrase offset method, when a passphrase
// was provided but the polyseed is not encrypted. // was provided but the polyseed is not encrypted.
monero_wallet_manager.restoreWalletFromPolyseedWithOffset( monero_wallet_manager.restoreWalletFromPolyseedWithOffset(
path: path, path: path,
password: password, password: password,
seed: polyseed.encode(lang, coin), seed: polyseed.encode(lang, coin),
seedOffset: passphrase??'', seedOffset: passphrase ?? '',
language: "English"); language: "English");
final wallet = MoneroWallet( final wallet = MoneroWallet(
@ -437,7 +526,8 @@ class MoneroWalletService extends WalletService<
if (walletFilesExist(path)) await repairOldAndroidWallet(name); if (walletFilesExist(path)) await repairOldAndroidWallet(name);
await monero_wallet_manager.openWalletAsync({'path': path, 'password': password}); await monero_wallet_manager
.openWalletAsync({'path': path, 'password': password});
final walletInfo = walletInfoSource.values final walletInfo = walletInfoSource.values
.firstWhere((info) => info.id == WalletBase.idFor(name, getType())); .firstWhere((info) => info.id == WalletBase.idFor(name, getType()));
final wallet = MoneroWallet( final wallet = MoneroWallet(

View file

@ -5,18 +5,23 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: _fe_analyzer_shared name: _fe_analyzer_shared
sha256: "4897882604d919befd350648c7f91926a9d5de99e67b455bf0917cc2362f4bb8" sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "47.0.0" version: "76.0.0"
_macros:
dependency: transitive
description: dart
source: sdk
version: "0.3.3"
analyzer: analyzer:
dependency: transitive dependency: transitive
description: description:
name: analyzer name: analyzer
sha256: "690e335554a8385bc9d787117d9eb52c0c03ee207a607e593de3c9d71b1cfe80" sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.7.0" version: "6.11.0"
args: args:
dependency: transitive dependency: transitive
description: description:
@ -41,6 +46,22 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.11.0" version: "2.11.0"
bip32:
dependency: "direct main"
description:
name: bip32
sha256: "54787cd7a111e9d37394aabbf53d1fc5e2e0e0af2cd01c459147a97c0e3f8a97"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
bip39:
dependency: "direct main"
description:
name: bip39
sha256: de1ee27ebe7d96b84bb3a04a4132a0a3007dcdd5ad27dd14aa87a29d97c45edc
url: "https://pub.dev"
source: hosted
version: "1.0.6"
blockchain_utils: blockchain_utils:
dependency: transitive dependency: transitive
description: description:
@ -66,6 +87,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.1" version: "2.1.1"
bs58check:
dependency: transitive
description:
name: bs58check
sha256: c4a164d42b25c2f6bc88a8beccb9fc7d01440f3c60ba23663a20a70faf484ea9
url: "https://pub.dev"
source: hosted
version: "1.0.2"
build: build:
dependency: transitive dependency: transitive
description: description:
@ -94,10 +123,10 @@ packages:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: build_resolvers name: build_resolvers
sha256: "687cf90a3951affac1bd5f9ecb5e3e90b60487f3d9cdc359bb310f8876bb02a6" sha256: b9e4fda21d846e192628e7a4f6deda6888c36b5b69ba02ff291a01fd529140f0
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.10" version: "2.4.4"
build_runner: build_runner:
dependency: "direct dev" dependency: "direct dev"
description: description:
@ -222,10 +251,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: dart_style name: dart_style
sha256: "7a03456c3490394c8e7665890333e91ae8a49be43542b616e414449ac358acd4" sha256: "7306ab8a2359a48d22310ad823521d723acfed60ee1f7e37388e8986853b6820"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.4" version: "2.3.8"
dbus: dbus:
dependency: transitive dependency: transitive
description: description:
@ -348,6 +377,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.6.0" version: "2.6.0"
hex:
dependency: transitive
description:
name: hex
sha256: "4e7cd54e4b59ba026432a6be2dd9d96e4c5205725194997193bf871703b82c4a"
url: "https://pub.dev"
source: hosted
version: "0.2.0"
hive: hive:
dependency: transitive dependency: transitive
description: description:
@ -360,10 +397,10 @@ packages:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: hive_generator name: hive_generator
sha256: "81fd20125cb2ce8fd23623d7744ffbaf653aae93706c9bd3bf7019ea0ace3938" sha256: "06cb8f58ace74de61f63500564931f9505368f45f98958bd7a6c35ba24159db4"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.3" version: "2.0.1"
http: http:
dependency: "direct main" dependency: "direct main"
description: description:
@ -468,6 +505,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.0" version: "1.3.0"
macros:
dependency: transitive
description:
name: macros
sha256: "1d9e801cd66f7ea3663c45fc708450db1fa57f988142c64289142c9b7ee80656"
url: "https://pub.dev"
source: hosted
version: "0.1.3-main.0"
matcher: matcher:
dependency: transitive dependency: transitive
description: description:
@ -512,10 +557,18 @@ packages:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: mobx_codegen name: mobx_codegen
sha256: d4beb9cea4b7b014321235f8fdc7c2193ee0fe1d1198e9da7403f8bc85c4407c sha256: "990da80722f7d7c0017dec92040b31545d625b15d40204c36a1e63d167c73cdc"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.0" version: "2.7.0"
mockito:
dependency: "direct dev"
description:
name: mockito
sha256: f99d8d072e249f719a5531735d146d8cf04c580d93920b04de75bef6dfb2daf6
url: "https://pub.dev"
source: hosted
version: "5.4.5"
monero: monero:
dependency: "direct main" dependency: "direct main"
description: description:
@ -735,18 +788,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: source_gen name: source_gen
sha256: "2d79738b6bbf38a43920e2b8d189e9a3ce6cc201f4b8fc76be5e4fe377b1c38d" sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.6" version: "1.5.0"
source_helper: source_helper:
dependency: transitive dependency: transitive
description: description:
name: source_helper name: source_helper
sha256: "3b67aade1d52416149c633ba1bb36df44d97c6b51830c2198e934e3fca87ca1f" sha256: "86d247119aedce8e63f4751bd9626fc9613255935558447569ad42f9f5b48b3c"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.3" version: "1.3.5"
source_span: source_span:
dependency: transitive dependency: transitive
description: description:
@ -924,5 +977,5 @@ packages:
source: hosted source: hosted
version: "3.1.3" version: "3.1.3"
sdks: sdks:
dart: ">=3.5.0 <4.0.0" dart: ">=3.6.0 <4.0.0"
flutter: ">=3.24.0" flutter: ">=3.24.0"

View file

@ -12,6 +12,8 @@ environment:
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
bip39: ^1.0.6
bip32: ^2.0.0
ffi: ^2.0.1 ffi: ^2.0.1
http: ^1.1.0 http: ^1.1.0
path_provider: ^2.0.11 path_provider: ^2.0.11
@ -36,7 +38,8 @@ dev_dependencies:
build_runner: ^2.4.7 build_runner: ^2.4.7
build_resolvers: ^2.0.9 build_resolvers: ^2.0.9
mobx_codegen: ^2.0.7 mobx_codegen: ^2.0.7
hive_generator: ^1.1.3 mockito: ^5.4.5
hive_generator: ^2.0.1
dependency_overrides: dependency_overrides:
watcher: ^1.1.0 watcher: ^1.1.0

View file

@ -0,0 +1,39 @@
import 'package:cw_monero/bip39_seed.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
group("Exodus Style bip39", () {
group("Test Wallet 1", () {
final bip39Seed = 'meadow tip best belt boss eyebrow control affair eternal piece very shiver';
final expectedLegacySeed0 = "tasked eight afraid laboratory tail feline rift reinvest vane cafe bailed foggy dormant paper jigsaw king hazard suture king dapper dummy jolted dating dwindling king";
final expectedLegacySeed1 = "palace pairing axes mohawk rekindle excess awful juvenile shipped talent nibs efficient dapper biggest swung fight pact innocent emerge issued titans affair nearby noises emerge";
test("Get legacy Seed from bip39", () {
final legacySeed = getLegacySeedFromBip39(bip39Seed);
expect(legacySeed, expectedLegacySeed0);
});
test("Get legacy Seed from bip39 with account index", () {
final legacySeed = getLegacySeedFromBip39(bip39Seed, accountIndex: 1);
expect(legacySeed, expectedLegacySeed1);
});
});
group("Test Wallet 2", () {
final bip39Seed = "color ranch color remove subway public water embrace before begin liberty fault";
final expectedLegacySeed0 = "somewhere problems gauze gigantic intended foxes upcoming saved waffle pipeline lurk bogeys empty wipeout abbey italics novelty tucks rafts elite lunar obnoxious awful bugs elite";
final expectedLegacySeed1 = "playful toxic wildly eluded mesh fainted february mugged maps repent vigilant hitched seventh threaten clue fetches sample diet number alkaline future cottage tuition vegan alkaline";
test("Get legacy Seed from bip39", () {
final legacySeed = getLegacySeedFromBip39(bip39Seed);
expect(legacySeed, expectedLegacySeed0);
});
test("Get legacy Seed from bip39 with account index", () {
final legacySeed = getLegacySeedFromBip39(bip39Seed, accountIndex: 1);
expect(legacySeed, expectedLegacySeed1);
});
});
});
}

View file

@ -0,0 +1,29 @@
import 'package:mockito/mockito.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:path_provider_platform_interface/path_provider_platform_interface.dart';
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
class MockPathProviderPlatform extends Mock
with MockPlatformInterfaceMixin
implements PathProviderPlatform {
Future<String> getTemporaryPath() => throw UnimplementedError();
Future<String> getApplicationSupportPath() => throw UnimplementedError();
Future<String> getLibraryPath() => throw UnimplementedError();
Future<String> getApplicationDocumentsPath() async => "./test/data";
Future<String> getExternalStoragePath() => throw UnimplementedError();
Future<List<String>> getExternalCachePaths() => throw UnimplementedError();
Future<String> getDownloadsPath() => throw UnimplementedError();
@override
Future<String?> getApplicationCachePath() => throw UnimplementedError();
@override
Future<List<String>?> getExternalStoragePaths({StorageDirectory? type}) =>
throw UnimplementedError();
}

View file

@ -0,0 +1,148 @@
import 'dart:io';
import 'package:cw_core/unspent_coins_info.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:cw_monero/monero_wallet_service.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:hive/hive.dart';
import 'package:path_provider_platform_interface/path_provider_platform_interface.dart';
import 'mock/path_provider.dart';
import 'utils/setup_monero_c.dart';
Future<void> main() async {
group("MoneroWalletService Tests", () {
Hive.init('./test/data/db');
late MoneroWalletService walletService;
late File moneroCBinary;
setUpAll(() async {
PathProviderPlatform.instance = MockPathProviderPlatform();
final Box<WalletInfo> walletInfoSource =
await Hive.openBox('testWalletInfo');
final Box<UnspentCoinsInfo> unspentCoinsInfoSource =
await Hive.openBox('testUnspentCoinsInfo');
walletService = MoneroWalletService(walletInfoSource, unspentCoinsInfoSource);
moneroCBinary = getMoneroCBinary().copySync(moneroCBinaryName);
});
tearDownAll(() {
Directory('./test/data').deleteSync(recursive: true);
moneroCBinary.deleteSync();
});
group("Create wallet", () {
test("Create Legacy Wallet", () async {
final credentials = _getTestCreateCredentials(
name: 'Create Wallet LS',
language: 'English',
seedType: MoneroSeedType.legacy);
final wallet = await walletService.create(credentials);
expect(wallet.seed.split(" ").length, 25);
expect(wallet.restoreHeight, greaterThan(3000000));
});
test("Create Polyseed Wallet", () async {
final credentials = _getTestCreateCredentials(
name: 'Create Wallet PS',
language: 'English',
seedType: MoneroSeedType.polyseed);
final wallet = await walletService.create(credentials);
expect(wallet.seed.split(" ").length, 16);
expect(wallet.restoreHeight, greaterThan(3000000));
});
test("Create Bip39 Wallet", () async {
final credentials = _getTestCreateCredentials(
name: 'Create Wallet BS',
language: 'English',
seedType: MoneroSeedType.bip39);
final wallet = await walletService.create(credentials);
expect(wallet.seed.split(" ").length, 12);
expect(wallet.restoreHeight, greaterThan(3000000));
});
});
group("Restore wallet", () {
test('Legacy Seed', () async {
final credentials = _getTestRestoreCredentials(
name: 'Test Wallet LS',
mnemonic:
'ability pockets lordship tomorrow gypsy match neutral uncle avatar betting bicycle junk unzip pyramid lynx mammal edgy empty uneven knowledge juvenile wiring paradise psychic betting',
);
final wallet = await walletService.restoreFromSeed(credentials);
expect(wallet.walletAddresses.primaryAddress,
'48tLyQXpcwt8w6uKHyb5Zs3vdnoDWAEKFQr1c198o7aX9dBzXP3BTSMVsDiuH3ozDCNqwojb4vNeQZf7xg6URimDLaNtGSN');
});
test('Bip39 Seed', () async {
final credentials = _getTestRestoreCredentials(
name: 'Test Wallet BS',
mnemonic:
'color ranch color remove subway public water embrace before begin liberty fault');
final wallet = await walletService.restoreFromSeed(credentials);
expect(wallet.walletAddresses.primaryAddress,
'49MggvPosJugF8Zq7WAKbsSchz6vbyL6YiUxM4ryfGQDXphs6wiWiXLFWCSshnLPcceGTWUaKfWWMHQAAKESV3TQJVQsL9a');
});
});
});
}
MoneroRestoreWalletFromSeedCredentials _getTestRestoreCredentials({
required String name,
required String mnemonic,
}) {
final credentials = MoneroRestoreWalletFromSeedCredentials(
name: name, mnemonic: mnemonic, passphrase: '', password: "test");
credentials.walletInfo = WalletInfo.external(
id: WalletBase.idFor(name, WalletType.monero),
name: name,
type: WalletType.monero,
isRecovery: true,
restoreHeight: credentials.height ?? 0,
date: DateTime.now(),
path: '',
dirPath: '',
address: '',
);
return credentials;
}
MoneroNewWalletCredentials _getTestCreateCredentials({
required String name,
required String language,
required MoneroSeedType seedType,
String? mnemonic,
}) {
final credentials = MoneroNewWalletCredentials(
name: name,
language: language,
seedType: seedType,
password: "test",
mnemonic: mnemonic,
passphrase: '',
);
credentials.walletInfo = WalletInfo.external(
id: WalletBase.idFor(name, WalletType.monero),
name: name,
type: WalletType.monero,
isRecovery: false,
restoreHeight: credentials.height ?? 0,
date: DateTime.now(),
path: '',
dirPath: '',
address: '',
);
return credentials;
}

View file

@ -0,0 +1,16 @@
import 'dart:io';
File getMoneroCBinary() {
if (Platform.isWindows)
return File(
'../scripts/monero_c/release/monero/x86_64-w64-mingw32_libwallet2_api_c.dll');
if (Platform.isMacOS) return File('../macos/monero_libwallet2_api_c.dylib');
return File('../scripts/monero_c/release/monero/x86_64-linux-gnu_libwallet2_api_c.so');
}
String get moneroCBinaryName {
if (Platform.isWindows)
return "monero_libwallet2_api_c.dll";
if (Platform.isMacOS) return "monero_libwallet2_api_c.dylib";
return "/usr/lib/monero_libwallet2_api_c.so";
}

View file

@ -1,17 +1,17 @@
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cw_core/enumerable_item.dart'; import 'package:cw_core/enumerable_item.dart';
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
class MoneroSeedType extends EnumerableItem<int> with Serializable<int> { class MoneroSeedType extends EnumerableItem<int> with Serializable<int> {
const MoneroSeedType({required String title, required int raw}) : super(title: title, raw: raw); const MoneroSeedType({required String title, required int raw}) : super(title: title, raw: raw);
static const all = [MoneroSeedType.legacy, MoneroSeedType.polyseed]; static const all = [legacy, polyseed, bip39];
static const defaultSeedType = polyseed; static const defaultSeedType = polyseed;
static const legacy = MoneroSeedType(raw: 0, title: 'Legacy (25 words)'); static const legacy = MoneroSeedType(raw: 0, title: 'Legacy');
static const polyseed = MoneroSeedType(raw: 1, title: 'Polyseed (16 words)'); static const polyseed = MoneroSeedType(raw: 1, title: 'Polyseed');
static const wowneroSeed = MoneroSeedType(raw: 2, title: 'Wownero (14 words)'); static const wowneroSeed = MoneroSeedType(raw: 2, title: 'Wownero');
static const bip39 = MoneroSeedType(raw: 3, title: 'BIP39');
static MoneroSeedType deserialize({required int raw}) { static MoneroSeedType deserialize({required int raw}) {
switch (raw) { switch (raw) {
@ -21,24 +21,15 @@ class MoneroSeedType extends EnumerableItem<int> with Serializable<int> {
return polyseed; return polyseed;
case 2: case 2:
return wowneroSeed; return wowneroSeed;
case 3:
return bip39;
default: default:
throw Exception('Unexpected token: $raw for SeedType deserialize'); throw Exception('Unexpected token: $raw for SeedType deserialize');
} }
} }
@override @override
String toString() { String toString() => title;
switch (this) {
case MoneroSeedType.legacy:
return S.current.seedtype_legacy;
case MoneroSeedType.polyseed:
return S.current.seedtype_polyseed;
case MoneroSeedType.wowneroSeed:
return S.current.seedtype_wownero;
default:
return '';
}
}
} }
class BitcoinSeedType extends EnumerableItem<int> with Serializable<int> { class BitcoinSeedType extends EnumerableItem<int> with Serializable<int> {

View file

@ -252,11 +252,21 @@ class CWMonero extends Monero {
WalletCredentials createMoneroNewWalletCredentials({ WalletCredentials createMoneroNewWalletCredentials({
required String name, required String name,
required String language, required String language,
required bool isPolyseed, required int seedType,
required String? passphrase, required String? passphrase,
String? password}) => String? password,
String? mnemonic,
}) =>
MoneroNewWalletCredentials( MoneroNewWalletCredentials(
name: name, password: password, language: language, isPolyseed: isPolyseed, passphrase: passphrase); name: name,
password: password,
language: language,
seedType: seedType == 1
? MoneroSeedType.polyseed
: (seedType == 3 ? MoneroSeedType.bip39 : MoneroSeedType.legacy),
passphrase: passphrase,
mnemonic: mnemonic,
);
@override @override
Map<String, String> getKeys(Object wallet) { Map<String, String> getKeys(Object wallet) {

View file

@ -11,8 +11,8 @@ bool isBIP39Wallet(WalletType walletType) {
case WalletType.bitcoinCash: case WalletType.bitcoinCash:
case WalletType.nano: case WalletType.nano:
case WalletType.banano: case WalletType.banano:
return true;
case WalletType.monero: case WalletType.monero:
return true;
case WalletType.wownero: case WalletType.wownero:
case WalletType.haven: case WalletType.haven:
case WalletType.zano: case WalletType.zano:

View file

@ -144,7 +144,9 @@ class _AdvancedPrivacySettingsBodyState extends State<_AdvancedPrivacySettingsBo
), ),
); );
}), }),
if (widget.privacySettingsViewModel.isMoneroSeedTypeOptionsEnabled) if (widget
.privacySettingsViewModel.isMoneroSeedTypeOptionsEnabled &&
!widget.isChildWallet)
Observer(builder: (_) { Observer(builder: (_) {
return SettingsChoicesCell( return SettingsChoicesCell(
ChoicesListItem<MoneroSeedType>( ChoicesListItem<MoneroSeedType>(

View file

@ -305,7 +305,7 @@ class _WalletNameFormState extends State<WalletNameForm> {
), ),
), ),
), ),
if (_walletNewVM.hasLanguageSelector) ...[ if (_walletNewVM.showLanguageSelector) ...[
if (_walletNewVM.hasSeedType) ...[ if (_walletNewVM.hasSeedType) ...[
Observer( Observer(
builder: (BuildContext build) => Padding( builder: (BuildContext build) => Padding(
@ -401,7 +401,11 @@ class _WalletNameFormState extends State<WalletNameForm> {
} else { } else {
await _walletNewVM.create( await _walletNewVM.create(
options: _walletNewVM.hasLanguageSelector options: _walletNewVM.hasLanguageSelector
? [_languageSelectorKey.currentState!.selected, isPolyseed] ? [
_languageSelectorKey.currentState?.selected ??
defaultSeedLanguage,
widget._seedSettingsViewModel.moneroSeedType
]
: null); : null);
} }
} catch (e) { } catch (e) {

View file

@ -11,13 +11,15 @@ import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/restore/restore_wallet.dart'; import 'package:cake_wallet/view_model/restore/restore_wallet.dart';
import 'package:cake_wallet/view_model/seed_settings_view_model.dart'; import 'package:cake_wallet/view_model/seed_settings_view_model.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:polyseed/polyseed.dart'; import 'package:polyseed/polyseed.dart';
class WalletRestoreFromSeedForm extends StatefulWidget { class WalletRestoreFromSeedForm extends StatefulWidget {
WalletRestoreFromSeedForm({Key? key, WalletRestoreFromSeedForm({
Key? key,
required this.displayLanguageSelector, required this.displayLanguageSelector,
required this.displayBlockHeightSelector, required this.displayBlockHeightSelector,
required this.type, required this.type,
@ -47,20 +49,22 @@ class WalletRestoreFromSeedForm extends StatefulWidget {
@override @override
WalletRestoreFromSeedFormState createState() => WalletRestoreFromSeedFormState createState() =>
WalletRestoreFromSeedFormState('English', displayWalletPassword: displayWalletPassword); WalletRestoreFromSeedFormState('English',
displayWalletPassword: displayWalletPassword);
} }
class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> { class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
WalletRestoreFromSeedFormState(this.language, {required bool displayWalletPassword}) WalletRestoreFromSeedFormState(this.language,
{required bool displayWalletPassword})
: seedWidgetStateKey = GlobalKey<SeedWidgetState>(), : seedWidgetStateKey = GlobalKey<SeedWidgetState>(),
blockchainHeightKey = GlobalKey<BlockchainHeightState>(), blockchainHeightKey = GlobalKey<BlockchainHeightState>(),
formKey = GlobalKey<FormState>(), formKey = GlobalKey<FormState>(),
languageController = TextEditingController(), languageController = TextEditingController(),
nameTextEditingController = TextEditingController(), nameTextEditingController = TextEditingController(),
passwordTextEditingController = displayWalletPassword ? TextEditingController() : null, passwordTextEditingController =
repeatedPasswordTextEditingController = displayWalletPassword displayWalletPassword ? TextEditingController() : null,
? TextEditingController() repeatedPasswordTextEditingController =
: null, displayWalletPassword ? TextEditingController() : null,
seedTypeController = TextEditingController(); seedTypeController = TextEditingController();
final GlobalKey<SeedWidgetState> seedWidgetStateKey; final GlobalKey<SeedWidgetState> seedWidgetStateKey;
@ -83,18 +87,21 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
_setLanguageLabel(language); _setLanguageLabel(language);
if (passwordTextEditingController != null) { if (passwordTextEditingController != null) {
passwordListener = () => widget.onPasswordChange?.call(passwordTextEditingController!.text); passwordListener = () =>
widget.onPasswordChange?.call(passwordTextEditingController!.text);
passwordTextEditingController?.addListener(passwordListener!); passwordTextEditingController?.addListener(passwordListener!);
} }
if (repeatedPasswordTextEditingController != null) { if (repeatedPasswordTextEditingController != null) {
repeatedPasswordListener = repeatedPasswordListener = () => widget.onRepeatedPasswordChange
() => widget.onRepeatedPasswordChange?.call(repeatedPasswordTextEditingController!.text); ?.call(repeatedPasswordTextEditingController!.text);
repeatedPasswordTextEditingController?.addListener(repeatedPasswordListener!); repeatedPasswordTextEditingController
?.addListener(repeatedPasswordListener!);
} }
moneroSeedTypeReaction = moneroSeedTypeReaction =
reaction((_) => widget.seedSettingsViewModel.moneroSeedType, (MoneroSeedType item) { reaction((_) => widget.seedSettingsViewModel.moneroSeedType,
(MoneroSeedType item) {
_setSeedType(item); _setSeedType(item);
_changeLanguage('English'); _changeLanguage('English');
}); });
@ -118,16 +125,22 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
} }
void onSeedChange(String seed) { void onSeedChange(String seed) {
if ((widget.type == WalletType.monero || widget.type == WalletType.wownero) && if ([WalletType.monero, WalletType.wownero].contains(widget.type) &&
Polyseed.isValidSeed(seed)) { (seed.split(" ").length == 12 || Polyseed.isValidSeed(seed))) {
try {
final lang = PolyseedLang.getByPhrase(seed); final lang = PolyseedLang.getByPhrase(seed);
if (widget.type == WalletType.monero && seed.split(" ").length == 12) {
_changeSeedType(MoneroSeedType.bip39);
} else {
_changeSeedType(MoneroSeedType.polyseed); _changeSeedType(MoneroSeedType.polyseed);
_changeLanguage(lang.nameEnglish);
} }
if (widget.type == WalletType.wownero && seed _changeLanguage(lang.nameEnglish, true);
.split(" ") } catch (e) {
.length == 14) { printV(e);
}
}
if (widget.type == WalletType.wownero && seed.split(" ").length == 14) {
_changeSeedType(MoneroSeedType.wowneroSeed); _changeSeedType(MoneroSeedType.wowneroSeed);
_changeLanguage("English"); _changeLanguage("English");
} }
@ -147,9 +160,7 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
BaseTextFormField( BaseTextFormField(
key: ValueKey('wallet_restore_from_seed_wallet_name_textfield_key'), key: ValueKey('wallet_restore_from_seed_wallet_name_textfield_key'),
controller: nameTextEditingController, controller: nameTextEditingController,
hintText: S hintText: S.of(context).wallet_name,
.of(context)
.wallet_name,
suffixIcon: IconButton( suffixIcon: IconButton(
key: ValueKey('wallet_restore_from_seed_wallet_name_refresh_button_key'), key: ValueKey('wallet_restore_from_seed_wallet_name_refresh_button_key'),
onPressed: () async { onPressed: () async {
@ -158,17 +169,17 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
setState(() { setState(() {
nameTextEditingController.text = rName; nameTextEditingController.text = rName;
nameTextEditingController.selection = TextSelection.fromPosition( nameTextEditingController.selection =
TextPosition(offset: nameTextEditingController.text.length)); TextSelection.fromPosition(TextPosition(
offset:
nameTextEditingController.text.length));
}); });
}, },
icon: Container( icon: Container(
padding: const EdgeInsets.all(8), padding: const EdgeInsets.all(8),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6.0), borderRadius: BorderRadius.circular(6.0),
color: Theme color: Theme.of(context).hintColor,
.of(context)
.hintColor,
), ),
width: 34, width: 34,
height: 34, height: 34,
@ -194,14 +205,13 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
seedTextFieldKey: ValueKey('wallet_restore_from_seed_wallet_seeds_textfield_key'), seedTextFieldKey: ValueKey('wallet_restore_from_seed_wallet_seeds_textfield_key'),
pasteButtonKey: ValueKey('wallet_restore_from_seed_wallet_seeds_paste_button_key'), pasteButtonKey: ValueKey('wallet_restore_from_seed_wallet_seeds_paste_button_key'),
), ),
if (widget.type == WalletType.monero || widget.type == WalletType.wownero) if ([WalletType.monero, WalletType.wownero].contains(widget.type))
GestureDetector( GestureDetector(
key: ValueKey('wallet_restore_from_seed_seedtype_picker_button_key'), key: ValueKey('wallet_restore_from_seed_seedtype_picker_button_key'),
onTap: () async { onTap: () async {
await showPopUp<void>( await showPopUp<void>(
context: context, context: context,
builder: (_) => builder: (_) => Picker(
Picker(
items: _getItems(), items: _getItems(),
selectedAtIndex: isPolyseed selectedAtIndex: isPolyseed
? 1 ? 1
@ -226,20 +236,16 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
), ),
), ),
), ),
if (widget.displayWalletPassword) if (widget.displayWalletPassword) ...[
...[BaseTextFormField( BaseTextFormField(
key: ValueKey('password'), key: ValueKey('password'),
controller: passwordTextEditingController, controller: passwordTextEditingController,
hintText: S hintText: S.of(context).password,
.of(context)
.password,
obscureText: true), obscureText: true),
BaseTextFormField( BaseTextFormField(
key: ValueKey('repeat_wallet_password'), key: ValueKey('repeat_wallet_password'),
controller: repeatedPasswordTextEditingController, controller: repeatedPasswordTextEditingController,
hintText: S hintText: S.of(context).repeat_wallet_password,
.of(context)
.repeat_wallet_password,
obscureText: true) obscureText: true)
], ],
if (widget.displayLanguageSelector) if (widget.displayLanguageSelector)
@ -248,11 +254,12 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
onTap: () async { onTap: () async {
await showPopUp<void>( await showPopUp<void>(
context: context, context: context,
builder: (_) => builder: (_) => SeedLanguagePicker(
SeedLanguagePicker(
selected: language, selected: language,
onItemSelected: _changeLanguage, onItemSelected: (lang) =>
seedType: isPolyseed ? MoneroSeedType.polyseed : MoneroSeedType.legacy, _changeLanguage(lang, isPolyseed || isBip39),
seedType:
widget.seedSettingsViewModel.moneroSeedType,
)); ));
}, },
child: Container( child: Container(
@ -274,7 +281,8 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
key: blockchainHeightKey, key: blockchainHeightKey,
blockHeightTextFieldKey: ValueKey('wallet_restore_from_seed_blockheight_textfield_key'), blockHeightTextFieldKey: ValueKey('wallet_restore_from_seed_blockheight_textfield_key'),
onHeightOrDateEntered: widget.onHeightOrDateEntered, onHeightOrDateEntered: widget.onHeightOrDateEntered,
hasDatePicker: widget.type == WalletType.monero || widget.type == WalletType.wownero, hasDatePicker:
[WalletType.monero, WalletType.wownero].contains(widget.type),
walletType: widget.type, walletType: widget.type,
), ),
])); ]));
@ -282,24 +290,25 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
bool get isPolyseed => bool get isPolyseed =>
widget.seedSettingsViewModel.moneroSeedType == MoneroSeedType.polyseed && widget.seedSettingsViewModel.moneroSeedType == MoneroSeedType.polyseed &&
(widget.type == WalletType.monero || widget.type == WalletType.wownero); [WalletType.monero, WalletType.wownero].contains(widget.type);
Widget get expandIcon => bool get isBip39 =>
Container( widget.seedSettingsViewModel.moneroSeedType == MoneroSeedType.bip39 &&
WalletType.monero == widget.type;
Widget get expandIcon => Container(
padding: EdgeInsets.all(18), padding: EdgeInsets.all(18),
width: 24, width: 24,
height: 24, height: 24,
child: Image.asset( child: Image.asset(
'assets/images/arrow_bottom_purple_icon.png', 'assets/images/arrow_bottom_purple_icon.png',
height: 8, height: 8,
color: Theme color: Theme.of(context).hintColor,
.of(context)
.hintColor,
), ),
); );
void _changeLanguage(String language) { void _changeLanguage(String language, [bool useBip39Wordlist = false]) {
final setLang = isPolyseed final setLang = useBip39Wordlist
? "POLYSEED_$language" ? "POLYSEED_$language"
: seedTypeController.value.text.contains("14") : seedTypeController.value.text.contains("14")
? "WOWSEED_" + language ? "WOWSEED_" + language
@ -312,8 +321,8 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
}); });
} }
void _setLanguageLabel(String language) => void _setLanguageLabel(String language) => languageController.text =
languageController.text = '${language.replaceAll("POLYSEED_", "")} (Seed language)'; '${language.replaceAll("POLYSEED_", "")} (Seed language)';
void _changeSeedType(MoneroSeedType item) { void _changeSeedType(MoneroSeedType item) {
_setSeedType(item); _setSeedType(item);
@ -328,9 +337,17 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
List<MoneroSeedType> _getItems() { List<MoneroSeedType> _getItems() {
switch (widget.type) { switch (widget.type) {
case WalletType.monero: case WalletType.monero:
return [MoneroSeedType.legacy, MoneroSeedType.polyseed]; return [
MoneroSeedType.legacy,
MoneroSeedType.polyseed,
MoneroSeedType.bip39
];
case WalletType.wownero: case WalletType.wownero:
return [MoneroSeedType.legacy, MoneroSeedType.polyseed, MoneroSeedType.wowneroSeed]; return [
MoneroSeedType.legacy,
MoneroSeedType.polyseed,
MoneroSeedType.wowneroSeed
];
default: default:
return [MoneroSeedType.legacy]; return [MoneroSeedType.legacy];
} }

View file

@ -527,25 +527,42 @@ class _WalletRestorePageBodyState extends State<_WalletRestorePageBody>
} }
bool _isValidSeed() { bool _isValidSeed() {
final seedPhrase = final seedPhrase = walletRestoreFromSeedFormKey
walletRestoreFromSeedFormKey.currentState!.seedWidgetStateKey.currentState!.text; .currentState!.seedWidgetStateKey.currentState!.text;
if (walletRestoreViewModel.isPolyseed(seedPhrase)) return true; if (walletRestoreViewModel.isPolyseed(seedPhrase)) return true;
final seedWords = seedPhrase.split(' '); final seedWords = seedPhrase.split(' ');
if (seedWords.length == 14 && walletRestoreViewModel.type == WalletType.wownero) return true; if (seedWords.length == 14 &&
if (seedWords.length == 26 && walletRestoreViewModel.type == WalletType.zano) return true; walletRestoreViewModel.type == WalletType.wownero) return true;
if (seedWords.length == 26 &&
walletRestoreViewModel.type == WalletType.zano) return true;
if ((walletRestoreViewModel.type == WalletType.monero || if (seedWords.length == 12 &&
walletRestoreViewModel.type == WalletType.wownero || walletRestoreViewModel.type == WalletType.monero) {
walletRestoreViewModel.type == WalletType.haven) && return walletRestoreFromSeedFormKey
seedWords.length != WalletRestoreViewModelBase.moneroSeedMnemonicLength) { .currentState
return false; ?.blockchainHeightKey
.currentState
?.restoreHeightController
.text
.isNotEmpty == true;
}
if ([WalletType.monero, WalletType.wownero, WalletType.haven]
.contains(walletRestoreViewModel.type) &&
seedWords.length ==
WalletRestoreViewModelBase.moneroSeedMnemonicLength) {
return true;
} }
// bip39: // bip39:
final validBip39SeedLengths = [12, 18, 24]; final validBip39SeedLengths = [12, 18, 24];
final nonBip39WalletTypes = [WalletType.monero, WalletType.wownero, WalletType.haven, WalletType.decred]; final nonBip39WalletTypes = [
WalletType.wownero,
WalletType.haven,
WalletType.decred
];
// if it's a bip39 wallet and the length is not valid return false // if it's a bip39 wallet and the length is not valid return false
if (!nonBip39WalletTypes.contains(walletRestoreViewModel.type) && if (!nonBip39WalletTypes.contains(walletRestoreViewModel.type) &&
!(validBip39SeedLengths.contains(seedWords.length))) { !(validBip39SeedLengths.contains(seedWords.length))) {
@ -558,8 +575,9 @@ class _WalletRestorePageBodyState extends State<_WalletRestorePageBody>
return false; return false;
} }
final words = final words = walletRestoreFromSeedFormKey
walletRestoreFromSeedFormKey.currentState!.seedWidgetStateKey.currentState!.words.toSet(); .currentState!.seedWidgetStateKey.currentState!.words
.toSet();
return seedWords.toSet().difference(words).toSet().isEmpty; return seedWords.toSet().difference(words).toSet().isEmpty;
} }

View file

@ -16,7 +16,7 @@ class SeedLanguagePickerOption {
final List<SeedLanguagePickerOption> seedLanguages = [ final List<SeedLanguagePickerOption> seedLanguages = [
SeedLanguagePickerOption('English', S.current.seed_language_english, SeedLanguagePickerOption('English', S.current.seed_language_english,
Image.asset('assets/images/flags/usa.png'), [MoneroSeedType.legacy, MoneroSeedType.polyseed]), Image.asset('assets/images/flags/usa.png'), [MoneroSeedType.legacy, MoneroSeedType.polyseed, MoneroSeedType.bip39]),
SeedLanguagePickerOption('Chinese (Simplified)', S.current.seed_language_chinese, SeedLanguagePickerOption('Chinese (Simplified)', S.current.seed_language_chinese,
Image.asset('assets/images/flags/chn.png'), [MoneroSeedType.legacy, MoneroSeedType.polyseed]), Image.asset('assets/images/flags/chn.png'), [MoneroSeedType.legacy, MoneroSeedType.polyseed]),
SeedLanguagePickerOption('Chinese (Traditional)', S.current.seed_language_chinese_traditional, SeedLanguagePickerOption('Chinese (Traditional)', S.current.seed_language_chinese_traditional,

View file

@ -6,6 +6,7 @@ import 'package:cake_wallet/store/app_store.dart';
import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart'; import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart'; import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart';
import 'package:cake_wallet/wallet_types.g.dart'; import 'package:cake_wallet/wallet_types.g.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
@ -127,12 +128,16 @@ abstract class WalletGroupsDisplayViewModelBase with Store {
bool isNonSeedWallet = wallet.isNonSeedWallet; bool isNonSeedWallet = wallet.isNonSeedWallet;
bool isNotMoneroBip39Wallet = wallet.type == WalletType.monero &&
wallet.derivationInfo?.derivationType != DerivationType.bip39;
// Exclude if any of these conditions are true // Exclude if any of these conditions are true
return isNonBIP39Wallet || return isNonBIP39Wallet ||
isNanoDerivationType || isNanoDerivationType ||
isElectrumDerivationType || isElectrumDerivationType ||
isSameTypeAsSelectedWallet || isSameTypeAsSelectedWallet ||
isNonSeedWallet; isNonSeedWallet ||
isNotMoneroBip39Wallet;
}); });
if (shouldExcludeGroup) continue; if (shouldExcludeGroup) continue;

View file

@ -63,14 +63,15 @@ abstract class WalletKeysViewModelBase with Store {
String get seed => _wallet.seed != null ? _wallet.seed! : ''; String get seed => _wallet.seed != null ? _wallet.seed! : '';
bool get isLegacySeedOnly => bool get isLegacySeedOnly =>
(_wallet.type == WalletType.monero || _wallet.type == WalletType.wownero) && [WalletType.monero, WalletType.wownero].contains(_wallet.type) &&
_wallet.seed != null && _wallet.seed != null &&
!Polyseed.isValidSeed(_wallet.seed!); !(Polyseed.isValidSeed(_wallet.seed!) ||
_wallet.seed!.split(' ').length == 12);
String get legacySeed { String get legacySeed {
if ((_wallet.type == WalletType.monero || _wallet.type == WalletType.wownero) && if ((_wallet.type == WalletType.monero || _wallet.type == WalletType.wownero) &&
_wallet.seed != null && _wallet.seed != null &&
Polyseed.isValidSeed(_wallet.seed!)) { (Polyseed.isValidSeed(_wallet.seed!) || _wallet.seed!.split(' ').length == 12)) {
final langName = PolyseedLang.getByPhrase(_wallet.seed!).nameEnglish; final langName = PolyseedLang.getByPhrase(_wallet.seed!).nameEnglish;
if (_wallet.type == WalletType.monero) { if (_wallet.type == WalletType.monero) {

View file

@ -49,6 +49,9 @@ abstract class WalletNewVMBase extends WalletCreationVM with Store {
bool get hasLanguageSelector => bool get hasLanguageSelector =>
[WalletType.monero, WalletType.haven, WalletType.wownero].contains(type); [WalletType.monero, WalletType.haven, WalletType.wownero].contains(type);
bool get showLanguageSelector =>
newWalletArguments?.mnemonic == null && hasLanguageSelector;
int get seedPhraseWordsLength { int get seedPhraseWordsLength {
switch (type) { switch (type) {
case WalletType.monero: case WalletType.monero:
@ -81,7 +84,9 @@ abstract class WalletNewVMBase extends WalletCreationVM with Store {
} }
} }
bool get hasSeedType => [WalletType.monero, WalletType.wownero].contains(type); bool get hasSeedType =>
newWalletArguments?.mnemonic == null &&
[WalletType.monero, WalletType.wownero].contains(type);
@override @override
WalletCredentials getCredentials(dynamic _options) { WalletCredentials getCredentials(dynamic _options) {
@ -96,7 +101,11 @@ abstract class WalletNewVMBase extends WalletCreationVM with Store {
language: options!.first as String, language: options!.first as String,
password: walletPassword, password: walletPassword,
passphrase: passphrase, passphrase: passphrase,
isPolyseed: options.last as bool); seedType: newWalletArguments!.mnemonic != null
? MoneroSeedType.bip39.raw
: (options.last as MoneroSeedType).raw,
mnemonic: newWalletArguments!.mnemonic,
);
case WalletType.bitcoin: case WalletType.bitcoin:
case WalletType.litecoin: case WalletType.litecoin:
return bitcoin!.createBitcoinNewWalletCredentials( return bitcoin!.createBitcoinNewWalletCredentials(

View file

@ -683,9 +683,6 @@
"seedtype": "البذور", "seedtype": "البذور",
"seedtype_alert_content": "مشاركة البذور مع محافظ أخرى ممكن فقط مع BIP39 Seedtype.", "seedtype_alert_content": "مشاركة البذور مع محافظ أخرى ممكن فقط مع BIP39 Seedtype.",
"seedtype_alert_title": "تنبيه البذور", "seedtype_alert_title": "تنبيه البذور",
"seedtype_legacy": "إرث (25 كلمة)",
"seedtype_polyseed": "بوليسيد (16 كلمة)",
"seedtype_wownero": "Wownero (14 كلمة)",
"select_backup_file": "حدد ملف النسخ الاحتياطي", "select_backup_file": "حدد ملف النسخ الاحتياطي",
"select_buy_provider_notice": "حدد مزود شراء أعلاه. يمكنك تخطي هذه الشاشة عن طريق تعيين مزود شراء الافتراضي في إعدادات التطبيق.", "select_buy_provider_notice": "حدد مزود شراء أعلاه. يمكنك تخطي هذه الشاشة عن طريق تعيين مزود شراء الافتراضي في إعدادات التطبيق.",
"select_destination": ".ﻲﻃﺎﻴﺘﺣﻻﺍ ﺦﺴﻨﻟﺍ ﻒﻠﻣ ﺔﻬﺟﻭ ﺪﻳﺪﺤﺗ ءﺎﺟﺮﻟﺍ", "select_destination": ".ﻲﻃﺎﻴﺘﺣﻻﺍ ﺦﺴﻨﻟﺍ ﻒﻠﻣ ﺔﻬﺟﻭ ﺪﻳﺪﺤﺗ ءﺎﺟﺮﻟﺍ",

View file

@ -683,9 +683,6 @@
"seedtype": "Семенна тип", "seedtype": "Семенна тип",
"seedtype_alert_content": "Споделянето на семена с други портфейли е възможно само с BIP39 Seedtype.", "seedtype_alert_content": "Споделянето на семена с други портфейли е възможно само с BIP39 Seedtype.",
"seedtype_alert_title": "Сигнал за семена", "seedtype_alert_title": "Сигнал за семена",
"seedtype_legacy": "Наследство (25 думи)",
"seedtype_polyseed": "Поли семе (16 думи)",
"seedtype_wownero": "Wownero (14 думи)",
"select_backup_file": "Избор на резервно копие", "select_backup_file": "Избор на резервно копие",
"select_buy_provider_notice": "Изберете доставчик на покупка по -горе. Можете да пропуснете този екран, като зададете вашия доставчик по подразбиране по подразбиране в настройките на приложението.", "select_buy_provider_notice": "Изберете доставчик на покупка по -горе. Можете да пропуснете този екран, като зададете вашия доставчик по подразбиране по подразбиране в настройките на приложението.",
"select_destination": "Моля, изберете дестинация за архивния файл.", "select_destination": "Моля, изберете дестинация за архивния файл.",

View file

@ -683,9 +683,6 @@
"seedtype": "SeedType", "seedtype": "SeedType",
"seedtype_alert_content": "Sdílení semen s jinými peněženkami je možné pouze u BIP39 SeedType.", "seedtype_alert_content": "Sdílení semen s jinými peněženkami je možné pouze u BIP39 SeedType.",
"seedtype_alert_title": "Upozornění seedtype", "seedtype_alert_title": "Upozornění seedtype",
"seedtype_legacy": "Legacy (25 slov)",
"seedtype_polyseed": "Polyseed (16 slov)",
"seedtype_wownero": "Wownero (14 slov)",
"select_backup_file": "Vybrat soubor se zálohou", "select_backup_file": "Vybrat soubor se zálohou",
"select_buy_provider_notice": "Vyberte výše uvedeného poskytovatele nákupu. Tuto obrazovku můžete přeskočit nastavením výchozího poskytovatele nákupu v nastavení aplikace.", "select_buy_provider_notice": "Vyberte výše uvedeného poskytovatele nákupu. Tuto obrazovku můžete přeskočit nastavením výchozího poskytovatele nákupu v nastavení aplikace.",
"select_destination": "Vyberte cíl pro záložní soubor.", "select_destination": "Vyberte cíl pro záložní soubor.",

View file

@ -684,9 +684,6 @@
"seedtype": "Seedtyp", "seedtype": "Seedtyp",
"seedtype_alert_content": "Das Teilen von Seeds mit anderen Wallet ist nur mit bip39 Seedype möglich.", "seedtype_alert_content": "Das Teilen von Seeds mit anderen Wallet ist nur mit bip39 Seedype möglich.",
"seedtype_alert_title": "Seedype-Alarm", "seedtype_alert_title": "Seedype-Alarm",
"seedtype_legacy": "Veraltet (25 Wörter)",
"seedtype_polyseed": "Polyseed (16 Wörter)",
"seedtype_wownero": "WOWNO (14 Wörter)",
"select_backup_file": "Sicherungsdatei auswählen", "select_backup_file": "Sicherungsdatei auswählen",
"select_buy_provider_notice": "Wählen Sie oben einen Anbieter kaufen. Sie können diese Seite überspringen, indem Sie Ihren Standard-Kaufanbieter in den App-Einstellungen festlegen.", "select_buy_provider_notice": "Wählen Sie oben einen Anbieter kaufen. Sie können diese Seite überspringen, indem Sie Ihren Standard-Kaufanbieter in den App-Einstellungen festlegen.",
"select_destination": "Bitte wählen Sie das Ziel für die Sicherungsdatei aus.", "select_destination": "Bitte wählen Sie das Ziel für die Sicherungsdatei aus.",

View file

@ -684,9 +684,6 @@
"seedtype": "Seedtype", "seedtype": "Seedtype",
"seedtype_alert_content": "Sharing seeds with other wallets is only possible with BIP39 SeedType.", "seedtype_alert_content": "Sharing seeds with other wallets is only possible with BIP39 SeedType.",
"seedtype_alert_title": "SeedType Alert", "seedtype_alert_title": "SeedType Alert",
"seedtype_legacy": "Legacy (25 words)",
"seedtype_polyseed": "Polyseed (16 words)",
"seedtype_wownero": "Wownero (14 words)",
"select_backup_file": "Select backup file", "select_backup_file": "Select backup file",
"select_buy_provider_notice": "Select a buy provider above. You can skip this screen by setting your default buy provider in app settings.", "select_buy_provider_notice": "Select a buy provider above. You can skip this screen by setting your default buy provider in app settings.",
"select_destination": "Please select destination for the backup file.", "select_destination": "Please select destination for the backup file.",

View file

@ -684,9 +684,6 @@
"seedtype": "Tipos de semillas", "seedtype": "Tipos de semillas",
"seedtype_alert_content": "Compartir semillas con otras billeteras solo es posible con semillas bip39 - un tipo específico de semilla.", "seedtype_alert_content": "Compartir semillas con otras billeteras solo es posible con semillas bip39 - un tipo específico de semilla.",
"seedtype_alert_title": "Alerta de tipo de semillas", "seedtype_alert_title": "Alerta de tipo de semillas",
"seedtype_legacy": "Semilla clásica-legacy (25 palabras)",
"seedtype_polyseed": "Poli-semilla (16 palabras)",
"seedtype_wownero": "Wownero (14 palabras)",
"select_backup_file": "Seleccionar archivo de respaldo", "select_backup_file": "Seleccionar archivo de respaldo",
"select_buy_provider_notice": "Selecciona un proveedor de compra arriba. Puede omitir esta pantalla configurando su proveedor de compra predeterminado en la configuración de la aplicación.", "select_buy_provider_notice": "Selecciona un proveedor de compra arriba. Puede omitir esta pantalla configurando su proveedor de compra predeterminado en la configuración de la aplicación.",
"select_destination": "Selecciona el destino del archivo de copia de seguridad.", "select_destination": "Selecciona el destino del archivo de copia de seguridad.",

View file

@ -683,9 +683,6 @@
"seedtype": "Type de graine", "seedtype": "Type de graine",
"seedtype_alert_content": "Le partage de graines avec d'autres portefeuilles n'est possible qu'avec le type de graine BIP39.", "seedtype_alert_content": "Le partage de graines avec d'autres portefeuilles n'est possible qu'avec le type de graine BIP39.",
"seedtype_alert_title": "Alerte Type de Graine", "seedtype_alert_title": "Alerte Type de Graine",
"seedtype_legacy": "Legacy (25 words)",
"seedtype_polyseed": "Polyseed (16 mots)",
"seedtype_wownero": "WOWNERO (14 mots)",
"select_backup_file": "Sélectionnez le fichier de sauvegarde", "select_backup_file": "Sélectionnez le fichier de sauvegarde",
"select_buy_provider_notice": "Sélectionnez un fournisseur d'achat ci-dessus. Vous pouvez ignorer cet écran en définissant votre fournisseur d'achat par défaut dans les paramètres de l'application.", "select_buy_provider_notice": "Sélectionnez un fournisseur d'achat ci-dessus. Vous pouvez ignorer cet écran en définissant votre fournisseur d'achat par défaut dans les paramètres de l'application.",
"select_destination": "Veuillez sélectionner la destination du fichier de sauvegarde.", "select_destination": "Veuillez sélectionner la destination du fichier de sauvegarde.",

View file

@ -685,9 +685,6 @@
"seedtype": "Seedtype", "seedtype": "Seedtype",
"seedtype_alert_content": "Raba tsaba tare da sauran wallets yana yiwuwa ne kawai tare da Bip39 seedtype.", "seedtype_alert_content": "Raba tsaba tare da sauran wallets yana yiwuwa ne kawai tare da Bip39 seedtype.",
"seedtype_alert_title": "Seedtype farke", "seedtype_alert_title": "Seedtype farke",
"seedtype_legacy": "Legacy (25 kalmomi)",
"seedtype_polyseed": "Polyseed (16 kalmomi)",
"seedtype_wownero": "WowRero (kalmomi 14)",
"select_backup_file": "Zaɓi fayil ɗin madadin", "select_backup_file": "Zaɓi fayil ɗin madadin",
"select_buy_provider_notice": "Zaɓi mai ba da kyauta a sama. Zaka iya tsallake wannan allon ta hanyar saita mai ba da isasshen busasshen mai ba da isasshen busasshiyar saiti.", "select_buy_provider_notice": "Zaɓi mai ba da kyauta a sama. Zaka iya tsallake wannan allon ta hanyar saita mai ba da isasshen busasshen mai ba da isasshen busasshiyar saiti.",
"select_destination": "Da fatan za a zaɓi wurin da za a yi wa madadin fayil ɗin.", "select_destination": "Da fatan za a zaɓi wurin da za a yi wa madadin fayil ɗin.",

View file

@ -685,9 +685,6 @@
"seedtype": "बीज", "seedtype": "बीज",
"seedtype_alert_content": "अन्य पर्स के साथ बीज साझा करना केवल BIP39 सीडटाइप के साथ संभव है।", "seedtype_alert_content": "अन्य पर्स के साथ बीज साझा करना केवल BIP39 सीडटाइप के साथ संभव है।",
"seedtype_alert_title": "बीजगणित अलर्ट", "seedtype_alert_title": "बीजगणित अलर्ट",
"seedtype_legacy": "विरासत (25 शब्द)",
"seedtype_polyseed": "पॉलीसीड (16 शब्द)",
"seedtype_wownero": "Wownero (14 शब्द)",
"select_backup_file": "बैकअप फ़ाइल का चयन करें", "select_backup_file": "बैकअप फ़ाइल का चयन करें",
"select_buy_provider_notice": "ऊपर एक खरीद प्रदाता का चयन करें। आप इस स्क्रीन को ऐप सेटिंग्स में अपना डिफ़ॉल्ट बाय प्रदाता सेट करके छोड़ सकते हैं।", "select_buy_provider_notice": "ऊपर एक खरीद प्रदाता का चयन करें। आप इस स्क्रीन को ऐप सेटिंग्स में अपना डिफ़ॉल्ट बाय प्रदाता सेट करके छोड़ सकते हैं।",
"select_destination": "कृपया बैकअप फ़ाइल के लिए गंतव्य का चयन करें।", "select_destination": "कृपया बैकअप फ़ाइल के लिए गंतव्य का चयन करें।",

View file

@ -683,9 +683,6 @@
"seedtype": "Sjemenska vrsta", "seedtype": "Sjemenska vrsta",
"seedtype_alert_content": "Dijeljenje sjemena s drugim novčanicima moguće je samo s BIP39 sjemenom.", "seedtype_alert_content": "Dijeljenje sjemena s drugim novčanicima moguće je samo s BIP39 sjemenom.",
"seedtype_alert_title": "Upozorenje o sjemenu", "seedtype_alert_title": "Upozorenje o sjemenu",
"seedtype_legacy": "Nasljeđe (25 riječi)",
"seedtype_polyseed": "Poliseed (16 riječi)",
"seedtype_wownero": "WANERO (14 riječi)",
"select_backup_file": "Odaberite datoteku sigurnosne kopije", "select_backup_file": "Odaberite datoteku sigurnosne kopije",
"select_buy_provider_notice": "Odaberite gornji davatelj kupnje. Ovaj zaslon možete preskočiti postavljanjem zadanog davatelja usluga kupnje u postavkama aplikacija.", "select_buy_provider_notice": "Odaberite gornji davatelj kupnje. Ovaj zaslon možete preskočiti postavljanjem zadanog davatelja usluga kupnje u postavkama aplikacija.",
"select_destination": "Odaberite odredište za datoteku sigurnosne kopije.", "select_destination": "Odaberite odredište za datoteku sigurnosne kopije.",

View file

@ -682,9 +682,6 @@
"seedtype": "Սերմի տեսակ", "seedtype": "Սերմի տեսակ",
"seedtype_alert_content": "Այլ դրամապանակներով սերմերի փոխանակումը հնարավոր է միայն BIP39 SEEDTYPE- ով:", "seedtype_alert_content": "Այլ դրամապանակներով սերմերի փոխանակումը հնարավոր է միայն BIP39 SEEDTYPE- ով:",
"seedtype_alert_title": "SEEDTYPE ALERT", "seedtype_alert_title": "SEEDTYPE ALERT",
"seedtype_legacy": "Legacy (25 բառ)",
"seedtype_polyseed": "Polyseed (16 բառ)",
"seedtype_wownero": "Wownero (14 բառ)",
"select_backup_file": "Ընտրել կրկնօրինակ ֆայլ", "select_backup_file": "Ընտրել կրկնօրինակ ֆայլ",
"select_buy_provider_notice": "Ընտրեք գնման մատակարարը վերևում։ Դուք կարող եք բաց թողնել այս էկրանը ձեր լռելայն գնման մատակարարը հավելվածի կարգավորումներում սահմանելով", "select_buy_provider_notice": "Ընտրեք գնման մատակարարը վերևում։ Դուք կարող եք բաց թողնել այս էկրանը ձեր լռելայն գնման մատակարարը հավելվածի կարգավորումներում սահմանելով",
"select_destination": "Խնդրում ենք ընտրել կրկնօրինակ ֆայլի նպատակակետը", "select_destination": "Խնդրում ենք ընտրել կրկնօրինակ ֆայլի նպատակակետը",

View file

@ -686,9 +686,6 @@
"seedtype": "Seedtype", "seedtype": "Seedtype",
"seedtype_alert_content": "Berbagi biji dengan dompet lain hanya dimungkinkan dengan BIP39 seedtype.", "seedtype_alert_content": "Berbagi biji dengan dompet lain hanya dimungkinkan dengan BIP39 seedtype.",
"seedtype_alert_title": "Peringatan seedtype", "seedtype_alert_title": "Peringatan seedtype",
"seedtype_legacy": "Legacy (25 kata)",
"seedtype_polyseed": "Polyseed (16 kata)",
"seedtype_wownero": "Wownero (14 kata)",
"select_backup_file": "Pilih file cadangan", "select_backup_file": "Pilih file cadangan",
"select_buy_provider_notice": "Pilih penyedia beli di atas. Anda dapat melewatkan layar ini dengan mengatur penyedia pembelian default Anda di pengaturan aplikasi.", "select_buy_provider_notice": "Pilih penyedia beli di atas. Anda dapat melewatkan layar ini dengan mengatur penyedia pembelian default Anda di pengaturan aplikasi.",
"select_destination": "Silakan pilih tujuan untuk file cadangan.", "select_destination": "Silakan pilih tujuan untuk file cadangan.",

View file

@ -684,9 +684,6 @@
"seedtype": "Seedtype", "seedtype": "Seedtype",
"seedtype_alert_content": "La condivisione di semi con altri portafogli è possibile solo con Bip39 SeedType.", "seedtype_alert_content": "La condivisione di semi con altri portafogli è possibile solo con Bip39 SeedType.",
"seedtype_alert_title": "Avviso seedType", "seedtype_alert_title": "Avviso seedType",
"seedtype_legacy": "Legacy (25 parole)",
"seedtype_polyseed": "Polyseed (16 parole)",
"seedtype_wownero": "Wownero (14 parole)",
"select_backup_file": "Seleziona file di backup", "select_backup_file": "Seleziona file di backup",
"select_buy_provider_notice": "Seleziona un provider di acquisto sopra. È possibile saltare questa schermata impostando il provider di acquisto predefinito nelle impostazioni dell'app.", "select_buy_provider_notice": "Seleziona un provider di acquisto sopra. È possibile saltare questa schermata impostando il provider di acquisto predefinito nelle impostazioni dell'app.",
"select_destination": "Seleziona la destinazione per il file di backup.", "select_destination": "Seleziona la destinazione per il file di backup.",

View file

@ -684,9 +684,6 @@
"seedtype": "SeedType", "seedtype": "SeedType",
"seedtype_alert_content": "他の財布と種子を共有することは、BIP39 SeedTypeでのみ可能です。", "seedtype_alert_content": "他の財布と種子を共有することは、BIP39 SeedTypeでのみ可能です。",
"seedtype_alert_title": "SeedTypeアラート", "seedtype_alert_title": "SeedTypeアラート",
"seedtype_legacy": "レガシー25語",
"seedtype_polyseed": "ポリシード16語",
"seedtype_wownero": "wownero14ワード",
"select_backup_file": "バックアップファイルを選択", "select_backup_file": "バックアップファイルを選択",
"select_buy_provider_notice": "上記の購入プロバイダーを選択してください。デフォルトの購入プロバイダーをアプリ設定で設定して、この画面をスキップできます。", "select_buy_provider_notice": "上記の購入プロバイダーを選択してください。デフォルトの購入プロバイダーをアプリ設定で設定して、この画面をスキップできます。",
"select_destination": "バックアップファイルの保存先を選択してください。", "select_destination": "バックアップファイルの保存先を選択してください。",

View file

@ -683,9 +683,6 @@
"seedtype": "시드 타입", "seedtype": "시드 타입",
"seedtype_alert_content": "다른 지갑과 씨앗을 공유하는 것은 BIP39 SeedType에서만 가능합니다.", "seedtype_alert_content": "다른 지갑과 씨앗을 공유하는 것은 BIP39 SeedType에서만 가능합니다.",
"seedtype_alert_title": "종자 경보", "seedtype_alert_title": "종자 경보",
"seedtype_legacy": "레거시 (25 단어)",
"seedtype_polyseed": "다문 (16 단어)",
"seedtype_wownero": "Wownero (14 단어)",
"select_backup_file": "백업 파일 선택", "select_backup_file": "백업 파일 선택",
"select_buy_provider_notice": "위의 구매 제공자를 선택하십시오. 앱 설정에서 기본 구매 제공자를 설정 하여이 화면을 건너 뛸 수 있습니다.", "select_buy_provider_notice": "위의 구매 제공자를 선택하십시오. 앱 설정에서 기본 구매 제공자를 설정 하여이 화면을 건너 뛸 수 있습니다.",
"select_destination": "백업 파일의 대상을 선택하십시오.", "select_destination": "백업 파일의 대상을 선택하십시오.",

View file

@ -683,9 +683,6 @@
"seedtype": "မျိုးပွားခြင်း", "seedtype": "မျိုးပွားခြင်း",
"seedtype_alert_content": "အခြားပိုက်ဆံအိတ်များနှင့်မျိုးစေ့များကိုမျှဝေခြင်းသည် BIP39 sebyspe ဖြင့်သာဖြစ်သည်။", "seedtype_alert_content": "အခြားပိုက်ဆံအိတ်များနှင့်မျိုးစေ့များကိုမျှဝေခြင်းသည် BIP39 sebyspe ဖြင့်သာဖြစ်သည်။",
"seedtype_alert_title": "ပျိုးပင်သတိပေးချက်", "seedtype_alert_title": "ပျိုးပင်သတိပေးချက်",
"seedtype_legacy": "အမွေအနှစ် (စကားလုံး 25 လုံး)",
"seedtype_polyseed": "polyseed (စကားလုံး 16 လုံး)",
"seedtype_wownero": "Wownero (စကားလုံး 14 လုံး)",
"select_backup_file": "အရန်ဖိုင်ကို ရွေးပါ။", "select_backup_file": "အရန်ဖိုင်ကို ရွေးပါ။",
"select_buy_provider_notice": "အပေါ်ကဝယ်သူတစ် ဦး ကိုရွေးချယ်ပါ။ သင်၏ default 0 ယ်သူအား app settings တွင် setting လုပ်ခြင်းဖြင့်ဤ screen ကိုကျော်သွားနိုင်သည်။", "select_buy_provider_notice": "အပေါ်ကဝယ်သူတစ် ဦး ကိုရွေးချယ်ပါ။ သင်၏ default 0 ယ်သူအား app settings တွင် setting လုပ်ခြင်းဖြင့်ဤ screen ကိုကျော်သွားနိုင်သည်။",
"select_destination": "အရန်ဖိုင်အတွက် ဦးတည်ရာကို ရွေးပါ။", "select_destination": "အရန်ဖိုင်အတွက် ဦးတည်ရာကို ရွေးပါ။",

View file

@ -683,9 +683,6 @@
"seedtype": "Zaadtype", "seedtype": "Zaadtype",
"seedtype_alert_content": "Het delen van zaden met andere portefeuilles is alleen mogelijk met BIP39 SeedType.", "seedtype_alert_content": "Het delen van zaden met andere portefeuilles is alleen mogelijk met BIP39 SeedType.",
"seedtype_alert_title": "Zaadtype alert", "seedtype_alert_title": "Zaadtype alert",
"seedtype_legacy": "Legacy (25 woorden)",
"seedtype_polyseed": "Polyseed (16 woorden)",
"seedtype_wownero": "WOWNERO (14 woorden)",
"select_backup_file": "Selecteer een back-upbestand", "select_backup_file": "Selecteer een back-upbestand",
"select_buy_provider_notice": "Selecteer hierboven een koopprovider. U kunt dit scherm overslaan door uw standaard kopenprovider in te stellen in app -instellingen.", "select_buy_provider_notice": "Selecteer hierboven een koopprovider. U kunt dit scherm overslaan door uw standaard kopenprovider in te stellen in app -instellingen.",
"select_destination": "Selecteer de bestemming voor het back-upbestand.", "select_destination": "Selecteer de bestemming voor het back-upbestand.",

View file

@ -683,9 +683,6 @@
"seedtype": "Sedtype", "seedtype": "Sedtype",
"seedtype_alert_content": "Dzielenie się nasionami z innymi portfelami jest możliwe tylko z BIP39 sededType.", "seedtype_alert_content": "Dzielenie się nasionami z innymi portfelami jest możliwe tylko z BIP39 sededType.",
"seedtype_alert_title": "Ustanowienie typu sedype", "seedtype_alert_title": "Ustanowienie typu sedype",
"seedtype_legacy": "Legacy (25 słów)",
"seedtype_polyseed": "Polyseed (16 słów)",
"seedtype_wownero": "Wowero (14 słów)",
"select_backup_file": "Wybierz plik kopii zapasowej", "select_backup_file": "Wybierz plik kopii zapasowej",
"select_buy_provider_notice": "Wybierz powyższe dostawcę zakupu. Możesz pominąć ten ekran, ustawiając domyślnego dostawcę zakupu w ustawieniach aplikacji.", "select_buy_provider_notice": "Wybierz powyższe dostawcę zakupu. Możesz pominąć ten ekran, ustawiając domyślnego dostawcę zakupu w ustawieniach aplikacji.",
"select_destination": "Wybierz miejsce docelowe dla pliku kopii zapasowej.", "select_destination": "Wybierz miejsce docelowe dla pliku kopii zapasowej.",

View file

@ -685,9 +685,6 @@
"seedtype": "SeedType", "seedtype": "SeedType",
"seedtype_alert_content": "Compartilhar sementes com outras carteiras só é possível com o BIP39 SeedType.", "seedtype_alert_content": "Compartilhar sementes com outras carteiras só é possível com o BIP39 SeedType.",
"seedtype_alert_title": "Alerta de SeedType", "seedtype_alert_title": "Alerta de SeedType",
"seedtype_legacy": "Legado (25 palavras)",
"seedtype_polyseed": "Polyseed (16 palavras)",
"seedtype_wownero": "Wowrone (14 palavras)",
"select_backup_file": "Selecione o arquivo de backup", "select_backup_file": "Selecione o arquivo de backup",
"select_buy_provider_notice": "Selecione um provedor de compra acima. Você pode pular esta tela definindo seu provedor de compra padrão nas configurações de aplicativos.", "select_buy_provider_notice": "Selecione um provedor de compra acima. Você pode pular esta tela definindo seu provedor de compra padrão nas configurações de aplicativos.",
"select_destination": "Selecione o destino para o arquivo de backup.", "select_destination": "Selecione o destino para o arquivo de backup.",

View file

@ -684,9 +684,6 @@
"seedtype": "SEEDTYPE", "seedtype": "SEEDTYPE",
"seedtype_alert_content": "Обмен семенами с другими кошельками возможно только с BIP39 SeedType.", "seedtype_alert_content": "Обмен семенами с другими кошельками возможно только с BIP39 SeedType.",
"seedtype_alert_title": "SEEDTYPE ALERT", "seedtype_alert_title": "SEEDTYPE ALERT",
"seedtype_legacy": "Наследие (25 слов)",
"seedtype_polyseed": "Полиса (16 слов)",
"seedtype_wownero": "Wownero (14 слов)",
"select_backup_file": "Выберите файл резервной копии", "select_backup_file": "Выберите файл резервной копии",
"select_buy_provider_notice": "Выберите поставщика покупки выше. Вы можете пропустить этот экран, установив поставщика покупки по умолчанию в настройках приложения.", "select_buy_provider_notice": "Выберите поставщика покупки выше. Вы можете пропустить этот экран, установив поставщика покупки по умолчанию в настройках приложения.",
"select_destination": "Пожалуйста, выберите место для файла резервной копии.", "select_destination": "Пожалуйста, выберите место для файла резервной копии.",

View file

@ -683,9 +683,6 @@
"seedtype": "เมล็ดพันธุ์", "seedtype": "เมล็ดพันธุ์",
"seedtype_alert_content": "การแบ่งปันเมล็ดกับกระเป๋าเงินอื่น ๆ เป็นไปได้เฉพาะกับ bip39 seedtype", "seedtype_alert_content": "การแบ่งปันเมล็ดกับกระเป๋าเงินอื่น ๆ เป็นไปได้เฉพาะกับ bip39 seedtype",
"seedtype_alert_title": "การแจ้งเตือน seedtype", "seedtype_alert_title": "การแจ้งเตือน seedtype",
"seedtype_legacy": "มรดก (25 คำ)",
"seedtype_polyseed": "โพลีส (16 คำ)",
"seedtype_wownero": "wownero (14 คำ)",
"select_backup_file": "เลือกไฟล์สำรอง", "select_backup_file": "เลือกไฟล์สำรอง",
"select_buy_provider_notice": "เลือกผู้ให้บริการซื้อด้านบน คุณสามารถข้ามหน้าจอนี้ได้โดยการตั้งค่าผู้ให้บริการซื้อเริ่มต้นในการตั้งค่าแอป", "select_buy_provider_notice": "เลือกผู้ให้บริการซื้อด้านบน คุณสามารถข้ามหน้าจอนี้ได้โดยการตั้งค่าผู้ให้บริการซื้อเริ่มต้นในการตั้งค่าแอป",
"select_destination": "โปรดเลือกปลายทางสำหรับไฟล์สำรอง", "select_destination": "โปรดเลือกปลายทางสำหรับไฟล์สำรอง",

View file

@ -683,9 +683,6 @@
"seedtype": "Seed type", "seedtype": "Seed type",
"seedtype_alert_content": "Ang pagbabahagi ng mga buto sa iba pang mga pitaka ay posible lamang sa bip39 seedtype.", "seedtype_alert_content": "Ang pagbabahagi ng mga buto sa iba pang mga pitaka ay posible lamang sa bip39 seedtype.",
"seedtype_alert_title": "Alerto ng Seedtype", "seedtype_alert_title": "Alerto ng Seedtype",
"seedtype_legacy": "Legacy (25 na salita)",
"seedtype_polyseed": "Polyseed (16 na salita)",
"seedtype_wownero": "Wownero (14 na salita)",
"select_backup_file": "Piliin ang backup na file", "select_backup_file": "Piliin ang backup na file",
"select_buy_provider_notice": "Pumili ng provider ng pagbili sa itaas. Maaari mong laktawan ang screen na ito sa pamamagitan ng pagtatakda ng iyong default na provider ng pagbili sa mga setting ng app.", "select_buy_provider_notice": "Pumili ng provider ng pagbili sa itaas. Maaari mong laktawan ang screen na ito sa pamamagitan ng pagtatakda ng iyong default na provider ng pagbili sa mga setting ng app.",
"select_destination": "Mangyaring piliin ang patutunguhan para sa backup na file.", "select_destination": "Mangyaring piliin ang patutunguhan para sa backup na file.",

View file

@ -683,9 +683,6 @@
"seedtype": "Tohum", "seedtype": "Tohum",
"seedtype_alert_content": "Tohumları diğer cüzdanlarla paylaşmak sadece BIP39 tohumu ile mümkündür.", "seedtype_alert_content": "Tohumları diğer cüzdanlarla paylaşmak sadece BIP39 tohumu ile mümkündür.",
"seedtype_alert_title": "SeedType uyarısı", "seedtype_alert_title": "SeedType uyarısı",
"seedtype_legacy": "Miras (25 kelime)",
"seedtype_polyseed": "Polyseed (16 kelime)",
"seedtype_wownero": "Wownero (14 kelime)",
"select_backup_file": "Yedek dosyası seç", "select_backup_file": "Yedek dosyası seç",
"select_buy_provider_notice": "Yukarıda bir satın alma sağlayıcısı seçin. App ayarlarında varsayılan satın alma sağlayıcınızı ayarlayarak bu ekranı atlayabilirsiniz.", "select_buy_provider_notice": "Yukarıda bir satın alma sağlayıcısı seçin. App ayarlarında varsayılan satın alma sağlayıcınızı ayarlayarak bu ekranı atlayabilirsiniz.",
"select_destination": "Lütfen yedekleme dosyası için hedef seçin.", "select_destination": "Lütfen yedekleme dosyası için hedef seçin.",

View file

@ -684,9 +684,6 @@
"seedtype": "Насіннєвий тип", "seedtype": "Насіннєвий тип",
"seedtype_alert_content": "Спільний доступ до інших гаманців можливе лише за допомогою BIP39 Seedtype.", "seedtype_alert_content": "Спільний доступ до інших гаманців можливе лише за допомогою BIP39 Seedtype.",
"seedtype_alert_title": "Попередження насінника", "seedtype_alert_title": "Попередження насінника",
"seedtype_legacy": "Спадщина (25 слів)",
"seedtype_polyseed": "Полісей (16 слів)",
"seedtype_wownero": "Влонеро (14 слів)",
"select_backup_file": "Виберіть файл резервної копії", "select_backup_file": "Виберіть файл резервної копії",
"select_buy_provider_notice": "Виберіть постачальника купівлі вище. Ви можете пропустити цей екран, встановивши свого постачальника купівлі за замовчуванням у налаштуваннях додатків.", "select_buy_provider_notice": "Виберіть постачальника купівлі вище. Ви можете пропустити цей екран, встановивши свого постачальника купівлі за замовчуванням у налаштуваннях додатків.",
"select_destination": "Виберіть місце призначення для файлу резервної копії.", "select_destination": "Виберіть місце призначення для файлу резервної копії.",

View file

@ -685,9 +685,6 @@
"seedtype": "سیڈ ٹائپ", "seedtype": "سیڈ ٹائپ",
"seedtype_alert_content": "دوسرے بٹوے کے ساتھ بیجوں کا اشتراک صرف BIP39 بیج ٹائپ کے ساتھ ہی ممکن ہے۔", "seedtype_alert_content": "دوسرے بٹوے کے ساتھ بیجوں کا اشتراک صرف BIP39 بیج ٹائپ کے ساتھ ہی ممکن ہے۔",
"seedtype_alert_title": "سیڈ ٹائپ الرٹ", "seedtype_alert_title": "سیڈ ٹائپ الرٹ",
"seedtype_legacy": "میراث (25 الفاظ)",
"seedtype_polyseed": "پالیسیڈ (16 الفاظ)",
"seedtype_wownero": "واونرو (14 الفاظ)",
"select_backup_file": "بیک اپ فائل کو منتخب کریں۔", "select_backup_file": "بیک اپ فائل کو منتخب کریں۔",
"select_buy_provider_notice": "اوپر خریدنے والا خریدنے والا منتخب کریں۔ آپ ایپ کی ترتیبات میں اپنے پہلے سے طے شدہ خریدنے والے کو ترتیب دے کر اس اسکرین کو چھوڑ سکتے ہیں۔", "select_buy_provider_notice": "اوپر خریدنے والا خریدنے والا منتخب کریں۔ آپ ایپ کی ترتیبات میں اپنے پہلے سے طے شدہ خریدنے والے کو ترتیب دے کر اس اسکرین کو چھوڑ سکتے ہیں۔",
"select_destination": "۔ﮟﯾﺮﮐ ﺏﺎﺨﺘﻧﺍ ﺎﮐ ﻝﺰﻨﻣ ﮯﯿﻟ ﮯﮐ ﻞﺋﺎﻓ ﭖﺍ ﮏﯿﺑ ﻡﺮﮐ ﮦﺍﺮﺑ", "select_destination": "۔ﮟﯾﺮﮐ ﺏﺎﺨﺘﻧﺍ ﺎﮐ ﻝﺰﻨﻣ ﮯﯿﻟ ﮯﮐ ﻞﺋﺎﻓ ﭖﺍ ﮏﯿﺑ ﻡﺮﮐ ﮦﺍﺮﺑ",

View file

@ -681,9 +681,6 @@
"seedtype": "Loại hạt giống", "seedtype": "Loại hạt giống",
"seedtype_alert_content": "Chia sẻ hạt giống với ví khác chỉ có thể với BIP39 SeedType.", "seedtype_alert_content": "Chia sẻ hạt giống với ví khác chỉ có thể với BIP39 SeedType.",
"seedtype_alert_title": "Cảnh báo hạt giống", "seedtype_alert_title": "Cảnh báo hạt giống",
"seedtype_legacy": "Di sản (25 từ)",
"seedtype_polyseed": "Polyseed (16 từ)",
"seedtype_wownero": "Wownero (14 từ)",
"select_backup_file": "Chọn tệp sao lưu", "select_backup_file": "Chọn tệp sao lưu",
"select_buy_provider_notice": "Chọn nhà cung cấp mua ở trên. Bạn có thể bỏ qua màn hình này bằng cách thiết lập nhà cung cấp mua mặc định trong cài đặt ứng dụng.", "select_buy_provider_notice": "Chọn nhà cung cấp mua ở trên. Bạn có thể bỏ qua màn hình này bằng cách thiết lập nhà cung cấp mua mặc định trong cài đặt ứng dụng.",
"select_destination": "Vui lòng chọn đích cho tệp sao lưu.", "select_destination": "Vui lòng chọn đích cho tệp sao lưu.",

View file

@ -684,9 +684,6 @@
"seedtype": "Irugbin-seetypu", "seedtype": "Irugbin-seetypu",
"seedtype_alert_content": "Pinpin awọn irugbin pẹlu awọn gedo miiran ṣee ṣe pẹlu Bip39 irugbin.", "seedtype_alert_content": "Pinpin awọn irugbin pẹlu awọn gedo miiran ṣee ṣe pẹlu Bip39 irugbin.",
"seedtype_alert_title": "Ṣajọpọ Seeytype", "seedtype_alert_title": "Ṣajọpọ Seeytype",
"seedtype_legacy": "Legacy (awọn ọrọ 25)",
"seedtype_polyseed": "Polyseed (awọn ọrọ 16)",
"seedtype_wownero": "Wowero (awọn ọrọ 14)",
"select_backup_file": "Select backup file", "select_backup_file": "Select backup file",
"select_buy_provider_notice": "Yan olupese Ra loke. O le skii iboju yii nipa ṣiṣeto olupese rẹ ni awọn eto App.", "select_buy_provider_notice": "Yan olupese Ra loke. O le skii iboju yii nipa ṣiṣeto olupese rẹ ni awọn eto App.",
"select_destination": "Jọwọ yan ibi ti o nlo fun faili afẹyinti.", "select_destination": "Jọwọ yan ibi ti o nlo fun faili afẹyinti.",

View file

@ -683,9 +683,6 @@
"seedtype": "籽粒", "seedtype": "籽粒",
"seedtype_alert_content": "只有BIP39籽粒可以与其他钱包共享种子。", "seedtype_alert_content": "只有BIP39籽粒可以与其他钱包共享种子。",
"seedtype_alert_title": "籽粒警报", "seedtype_alert_title": "籽粒警报",
"seedtype_legacy": "遗产25个单词",
"seedtype_polyseed": "多种物品16个单词",
"seedtype_wownero": "沃恩罗14个单词",
"select_backup_file": "选择备份文件", "select_backup_file": "选择备份文件",
"select_buy_provider_notice": "在上面选择买入提供商。您可以通过在应用程序设置中设置默认的购买提供商来跳过此屏幕。", "select_buy_provider_notice": "在上面选择买入提供商。您可以通过在应用程序设置中设置默认的购买提供商来跳过此屏幕。",
"select_destination": "请选择备份文件的目的地。", "select_destination": "请选择备份文件的目的地。",

View file

@ -406,7 +406,7 @@ abstract class Monero {
required int height}); required int height});
WalletCredentials createMoneroRestoreWalletFromSeedCredentials({required String name, required String password, required String passphrase, required int height, required String mnemonic}); WalletCredentials createMoneroRestoreWalletFromSeedCredentials({required String name, required String password, required String passphrase, required int height, required String mnemonic});
WalletCredentials createMoneroRestoreWalletFromHardwareCredentials({required String name, required String password, required int height, required ledger.LedgerConnection ledgerConnection}); WalletCredentials createMoneroRestoreWalletFromHardwareCredentials({required String name, required String password, required int height, required ledger.LedgerConnection ledgerConnection});
WalletCredentials createMoneroNewWalletCredentials({required String name, required String language, required bool isPolyseed, required String? passphrase, String? password}); WalletCredentials createMoneroNewWalletCredentials({required String name, required String language, required int seedType, required String? passphrase, String? password, String? mnemonic});
Map<String, String> getKeys(Object wallet); Map<String, String> getKeys(Object wallet);
int? getRestoreHeight(Object wallet); int? getRestoreHeight(Object wallet);
Object createMoneroTransactionCreationCredentials({required List<Output> outputs, required TransactionPriority priority}); Object createMoneroTransactionCreationCredentials({required List<Output> outputs, required TransactionPriority priority});