Ledger monero fix (#1834)

* Fix sending for monero ledger

* Ignore no tx keys found error

* re-add Monero to Ledger enabled wallets

* Fix No Element Exception on requireHardwareWalletConnection check

* Fix Showing connection screen again

* Maybe fix Race condition

* fix namespace

* Maybe fix Race condition and add missing pop

* Minor fixes

* Minor fixes

* Fix minor localization

* Fix minor localization

* Add Text prompt if device is not showing after 10 seconds.

---------

Co-authored-by: OmarHatem <omarh.ismail1@gmail.com>
Co-authored-by: Czarek Nakamoto <cyjan@mrcyjanek.net>
This commit is contained in:
Konstantin Ullrich 2024-12-14 00:32:36 +01:00 committed by GitHub
parent c620d7f486
commit ae758756d8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
41 changed files with 287 additions and 90 deletions

View file

@ -7,7 +7,7 @@ enum DeviceConnectionType {
static List<DeviceConnectionType> supportedConnectionTypes(WalletType walletType, static List<DeviceConnectionType> supportedConnectionTypes(WalletType walletType,
[bool isIOS = false]) { [bool isIOS = false]) {
switch (walletType) { switch (walletType) {
// case WalletType.monero: case WalletType.monero:
case WalletType.bitcoin: case WalletType.bitcoin:
case WalletType.litecoin: case WalletType.litecoin:
case WalletType.ethereum: case WalletType.ethereum:

View file

@ -200,9 +200,16 @@ String? commitTransactionFromPointerAddress({required int address, required bool
commitTransaction(transactionPointer: monero.PendingTransaction.fromAddress(address), useUR: useUR); commitTransaction(transactionPointer: monero.PendingTransaction.fromAddress(address), useUR: useUR);
String? commitTransaction({required monero.PendingTransaction transactionPointer, required bool useUR}) { String? commitTransaction({required monero.PendingTransaction transactionPointer, required bool useUR}) {
final transactionPointerAddress = transactionPointer.address;
final txCommit = useUR final txCommit = useUR
? monero.PendingTransaction_commitUR(transactionPointer, 120) ? monero.PendingTransaction_commitUR(transactionPointer, 120)
: monero.PendingTransaction_commit(transactionPointer, filename: '', overwrite: false); : Isolate.run(() {
monero.PendingTransaction_commit(
Pointer.fromAddress(transactionPointerAddress),
filename: '',
overwrite: false,
);
});
String? error = (() { String? error = (() {
final status = monero.PendingTransaction_status(transactionPointer.cast()); final status = monero.PendingTransaction_status(transactionPointer.cast());
@ -221,7 +228,7 @@ String? commitTransaction({required monero.PendingTransaction transactionPointer
})(); })();
} }
if (error != null) { if (error != null && error != "no tx keys found for this txid") {
throw CreationTransactionException(message: error); throw CreationTransactionException(message: error);
} }
if (useUR) { if (useUR) {

View file

@ -2,11 +2,12 @@ import 'dart:async';
import 'dart:ffi'; import 'dart:ffi';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:collection/collection.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:ffi/ffi.dart'; import 'package:ffi/ffi.dart';
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart'; import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';
import 'package:ledger_flutter_plus/ledger_flutter_plus_dart.dart'; import 'package:ledger_flutter_plus/ledger_flutter_plus_dart.dart';
import 'package:monero/monero.dart' as monero; import 'package:monero/monero.dart' as monero;
// import 'package:polyseed/polyseed.dart';
LedgerConnection? gLedger; LedgerConnection? gLedger;
@ -28,9 +29,16 @@ void enableLedgerExchange(monero.wallet ptr, LedgerConnection connection) {
ptr, emptyPointer.cast<UnsignedChar>(), 0); ptr, emptyPointer.cast<UnsignedChar>(), 0);
malloc.free(emptyPointer); malloc.free(emptyPointer);
// printV("> ${ledgerRequest.toHexString()}"); _logLedgerCommand(ledgerRequest, false);
final response = await exchange(connection, ledgerRequest); final response = await exchange(connection, ledgerRequest);
// printV("< ${response.toHexString()}"); _logLedgerCommand(response, true);
if (ListEquality().equals(response, [0x55, 0x15])) {
await connection.disconnect();
// // TODO: Show POPUP pls unlock your device
// await Future.delayed(Duration(seconds: 15));
// response = await exchange(connection, ledgerRequest);
}
final Pointer<Uint8> result = malloc<Uint8>(response.length); final Pointer<Uint8> result = malloc<Uint8>(response.length);
for (var i = 0; i < response.length; i++) { for (var i = 0; i < response.length; i++) {
@ -82,3 +90,59 @@ class ExchangeOperation extends LedgerRawOperation<Uint8List> {
@override @override
Future<List<Uint8List>> write(ByteDataWriter writer) async => [inputData]; Future<List<Uint8List>> write(ByteDataWriter writer) async => [inputData];
} }
const _ledgerMoneroCommands = {
0x00: "INS_NONE",
0x02: "INS_RESET",
0x20: "INS_GET_KEY",
0x21: "INS_DISPLAY_ADDRESS",
0x22: "INS_PUT_KEY",
0x24: "INS_GET_CHACHA8_PREKEY",
0x26: "INS_VERIFY_KEY",
0x28: "INS_MANAGE_SEEDWORDS",
0x30: "INS_SECRET_KEY_TO_PUBLIC_KEY",
0x32: "INS_GEN_KEY_DERIVATION",
0x34: "INS_DERIVATION_TO_SCALAR",
0x36: "INS_DERIVE_PUBLIC_KEY",
0x38: "INS_DERIVE_SECRET_KEY",
0x3A: "INS_GEN_KEY_IMAGE",
0x3B: "INS_DERIVE_VIEW_TAG",
0x3C: "INS_SECRET_KEY_ADD",
0x3E: "INS_SECRET_KEY_SUB",
0x40: "INS_GENERATE_KEYPAIR",
0x42: "INS_SECRET_SCAL_MUL_KEY",
0x44: "INS_SECRET_SCAL_MUL_BASE",
0x46: "INS_DERIVE_SUBADDRESS_PUBLIC_KEY",
0x48: "INS_GET_SUBADDRESS",
0x4A: "INS_GET_SUBADDRESS_SPEND_PUBLIC_KEY",
0x4C: "INS_GET_SUBADDRESS_SECRET_KEY",
0x70: "INS_OPEN_TX",
0x72: "INS_SET_SIGNATURE_MODE",
0x74: "INS_GET_ADDITIONAL_KEY",
0x76: "INS_STEALTH",
0x77: "INS_GEN_COMMITMENT_MASK",
0x78: "INS_BLIND",
0x7A: "INS_UNBLIND",
0x7B: "INS_GEN_TXOUT_KEYS",
0x7D: "INS_PREFIX_HASH",
0x7C: "INS_VALIDATE",
0x7E: "INS_MLSAG",
0x7F: "INS_CLSAG",
0x80: "INS_CLOSE_TX",
0xA0: "INS_GET_TX_PROOF",
0xC0: "INS_GET_RESPONSE"
};
void _logLedgerCommand(Uint8List command, [bool isResponse = true]) {
String toHexString(Uint8List data) =>
data.map((e) => e.toRadixString(16).padLeft(2, '0')).join();
if (isResponse) {
printV("< ${toHexString(command)}");
} else {
printV(
"> ${_ledgerMoneroCommands[command[1]]} ${toHexString(command.sublist(2))}");
}
}

View file

@ -1,5 +1,7 @@
import 'dart:ffi'; import 'dart:ffi';
import 'dart:io'; import 'dart:io';
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';
import 'package:cw_core/unspent_coins_info.dart'; import 'package:cw_core/unspent_coins_info.dart';
@ -9,16 +11,16 @@ import 'package:cw_core/wallet_credentials.dart';
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_service.dart'; import 'package:cw_core/wallet_service.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
import 'package:cw_core/get_height_by_date.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/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:polyseed/polyseed.dart';
import 'package:monero/monero.dart' as monero; import 'package:monero/monero.dart' as monero;
import 'package:polyseed/polyseed.dart';
class MoneroNewWalletCredentials extends WalletCredentials { class MoneroNewWalletCredentials extends WalletCredentials {
MoneroNewWalletCredentials( MoneroNewWalletCredentials(
@ -133,14 +135,12 @@ class MoneroWalletService extends WalletService<
try { try {
final path = await pathForWallet(name: name, type: getType()); final path = await pathForWallet(name: name, type: getType());
if (walletFilesExist(path)) { if (walletFilesExist(path)) await repairOldAndroidWallet(name);
await repairOldAndroidWallet(name);
}
await monero_wallet_manager await monero_wallet_manager
.openWalletAsync({'path': path, 'password': password}); .openWalletAsync({'path': path, 'password': password});
final walletInfo = walletInfoSource.values.firstWhere( final walletInfo = walletInfoSource.values
(info) => info.id == WalletBase.idFor(name, getType())); .firstWhere((info) => info.id == WalletBase.idFor(name, getType()));
final wallet = MoneroWallet( final wallet = MoneroWallet(
walletInfo: walletInfo, walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfoSource, unspentCoinsInfo: unspentCoinsInfoSource,
@ -255,7 +255,7 @@ class MoneroWalletService extends WalletService<
final password = credentials.password; final password = credentials.password;
final height = credentials.height; final height = credentials.height;
if (wptr == null ) monero_wallet_manager.createWalletPointer(); if (wptr == null) monero_wallet_manager.createWalletPointer();
enableLedgerExchange(wptr!, credentials.ledgerConnection); enableLedgerExchange(wptr!, credentials.ledgerConnection);
await monero_wallet_manager.restoreWalletFromHardwareWallet( await monero_wallet_manager.restoreWalletFromHardwareWallet(
@ -279,7 +279,8 @@ class MoneroWalletService extends WalletService<
} }
@override @override
Future<MoneroWallet> restoreFromSeed(MoneroRestoreWalletFromSeedCredentials credentials, Future<MoneroWallet> restoreFromSeed(
MoneroRestoreWalletFromSeedCredentials credentials,
{bool? isTestnet}) async { {bool? isTestnet}) async {
// Restore from Polyseed // Restore from Polyseed
if (Polyseed.isValidSeed(credentials.mnemonic)) { if (Polyseed.isValidSeed(credentials.mnemonic)) {
@ -313,7 +314,8 @@ class MoneroWalletService extends WalletService<
final path = await pathForWallet(name: credentials.name, type: getType()); final path = await pathForWallet(name: credentials.name, type: getType());
final polyseedCoin = PolyseedCoin.POLYSEED_MONERO; final polyseedCoin = PolyseedCoin.POLYSEED_MONERO;
final lang = PolyseedLang.getByPhrase(credentials.mnemonic); final lang = PolyseedLang.getByPhrase(credentials.mnemonic);
final polyseed = Polyseed.decode(credentials.mnemonic, lang, polyseedCoin); final polyseed =
Polyseed.decode(credentials.mnemonic, lang, polyseedCoin);
return _restoreFromPolyseed( return _restoreFromPolyseed(
path, credentials.password!, polyseed, credentials.walletInfo!, lang); path, credentials.password!, polyseed, credentials.walletInfo!, lang);
@ -355,24 +357,18 @@ class MoneroWalletService extends WalletService<
Future<void> repairOldAndroidWallet(String name) async { Future<void> repairOldAndroidWallet(String name) async {
try { try {
if (!Platform.isAndroid) { if (!Platform.isAndroid) return;
return;
}
final oldAndroidWalletDirPath = await outdatedAndroidPathForWalletDir(name: name); final oldAndroidWalletDirPath = await outdatedAndroidPathForWalletDir(name: name);
final dir = Directory(oldAndroidWalletDirPath); final dir = Directory(oldAndroidWalletDirPath);
if (!dir.existsSync()) { if (!dir.existsSync()) return;
return;
}
final newWalletDirPath = await pathForWalletDir(name: name, type: getType()); final newWalletDirPath = await pathForWalletDir(name: name, type: getType());
dir.listSync().forEach((f) { dir.listSync().forEach((f) {
final file = File(f.path); final file = File(f.path);
final name = f.path final name = f.path.split('/').last;
.split('/')
.last;
final newPath = newWalletDirPath + '/$name'; final newPath = newWalletDirPath + '/$name';
final newFile = File(newPath); final newFile = File(newPath);
@ -391,9 +387,7 @@ class MoneroWalletService extends WalletService<
try { try {
final path = await pathForWallet(name: name, type: getType()); final path = await pathForWallet(name: name, type: getType());
if (walletFilesExist(path)) { if (walletFilesExist(path)) await repairOldAndroidWallet(name);
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
@ -412,8 +406,10 @@ class MoneroWalletService extends WalletService<
@override @override
bool requireHardwareWalletConnection(String name) { bool requireHardwareWalletConnection(String name) {
final walletInfo = walletInfoSource.values return walletInfoSource.values
.firstWhere((info) => info.id == WalletBase.idFor(name, getType())); .firstWhereOrNull(
return walletInfo.isHardwareWallet; (info) => info.id == WalletBase.idFor(name, getType()))
?.isHardwareWallet ??
false;
} }
} }

View file

@ -44,13 +44,16 @@ void startAuthenticationStateChange(
} catch (error, stack) { } catch (error, stack) {
loginError = error; loginError = error;
await ExceptionHandler.resetLastPopupDate(); await ExceptionHandler.resetLastPopupDate();
await ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stack)); await ExceptionHandler.onError(
FlutterErrorDetails(exception: error, stack: stack));
} }
return; return;
} }
if (state == AuthenticationState.allowed) { if ([AuthenticationState.allowed, AuthenticationState.allowedCreate]
if (requireHardwareWalletConnection()) { .contains(state)) {
if (state == AuthenticationState.allowed &&
requireHardwareWalletConnection()) {
await navigatorKey.currentState!.pushNamedAndRemoveUntil( await navigatorKey.currentState!.pushNamedAndRemoveUntil(
Routes.connectDevices, Routes.connectDevices,
(route) => false, (route) => false,

View file

@ -22,11 +22,13 @@ class ConnectDevicePageParams {
final WalletType walletType; final WalletType walletType;
final OnConnectDevice onConnectDevice; final OnConnectDevice onConnectDevice;
final bool allowChangeWallet; final bool allowChangeWallet;
final bool isReconnect;
ConnectDevicePageParams({ ConnectDevicePageParams({
required this.walletType, required this.walletType,
required this.onConnectDevice, required this.onConnectDevice,
this.allowChangeWallet = false, this.allowChangeWallet = false,
this.isReconnect = false,
}); });
} }
@ -34,19 +36,33 @@ class ConnectDevicePage extends BasePage {
final WalletType walletType; final WalletType walletType;
final OnConnectDevice onConnectDevice; final OnConnectDevice onConnectDevice;
final bool allowChangeWallet; final bool allowChangeWallet;
final bool isReconnect;
final LedgerViewModel ledgerVM; final LedgerViewModel ledgerVM;
ConnectDevicePage(ConnectDevicePageParams params, this.ledgerVM) ConnectDevicePage(ConnectDevicePageParams params, this.ledgerVM)
: walletType = params.walletType, : walletType = params.walletType,
onConnectDevice = params.onConnectDevice, onConnectDevice = params.onConnectDevice,
allowChangeWallet = params.allowChangeWallet; allowChangeWallet = params.allowChangeWallet,
isReconnect = params.isReconnect;
@override @override
String get title => S.current.restore_title_from_hardware_wallet; String get title => isReconnect
? S.current.reconnect_your_hardware_wallet
: S.current.restore_title_from_hardware_wallet;
@override @override
Widget body(BuildContext context) => ConnectDevicePageBody( Widget? leading(BuildContext context) =>
walletType, onConnectDevice, allowChangeWallet, ledgerVM); !isReconnect ? super.leading(context) : null;
@override
Widget body(BuildContext context) => PopScope(
canPop: !isReconnect,
child: ConnectDevicePageBody(
walletType,
onConnectDevice,
allowChangeWallet,
ledgerVM,
));
} }
class ConnectDevicePageBody extends StatefulWidget { class ConnectDevicePageBody extends StatefulWidget {
@ -75,6 +91,8 @@ class ConnectDevicePageBodyState extends State<ConnectDevicePageBody> {
late Timer? _bleStateTimer = null; late Timer? _bleStateTimer = null;
late StreamSubscription<LedgerDevice>? _bleRefresh = null; late StreamSubscription<LedgerDevice>? _bleRefresh = null;
bool longWait = false;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@ -89,6 +107,11 @@ class ConnectDevicePageBodyState extends State<ConnectDevicePageBody> {
_usbRefreshTimer = _usbRefreshTimer =
Timer.periodic(Duration(seconds: 1), (_) => _refreshUsbDevices()); Timer.periodic(Duration(seconds: 1), (_) => _refreshUsbDevices());
} }
Future.delayed(Duration(seconds: 10), () {
if (widget.ledgerVM.bleIsEnabled && bleDevices.isEmpty)
setState(() => longWait = true);
});
}); });
} }
@ -98,6 +121,8 @@ class ConnectDevicePageBodyState extends State<ConnectDevicePageBody> {
_bleStateTimer?.cancel(); _bleStateTimer?.cancel();
_usbRefreshTimer?.cancel(); _usbRefreshTimer?.cancel();
_bleRefresh?.cancel(); _bleRefresh?.cancel();
widget.ledgerVM.stopScanning();
super.dispose(); super.dispose();
} }
@ -118,9 +143,11 @@ class ConnectDevicePageBodyState extends State<ConnectDevicePageBody> {
Future<void> _refreshBleDevices() async { Future<void> _refreshBleDevices() async {
try { try {
if (widget.ledgerVM.bleIsEnabled) { if (widget.ledgerVM.bleIsEnabled) {
_bleRefresh = widget.ledgerVM _bleRefresh =
.scanForBleDevices() widget.ledgerVM.scanForBleDevices().listen((device) => setState(() {
.listen((device) => setState(() => bleDevices.add(device))) bleDevices.add(device);
if (longWait) longWait = false;
}))
..onError((e) { ..onError((e) {
throw e.toString(); throw e.toString();
}); });
@ -175,15 +202,21 @@ class ConnectDevicePageBodyState extends State<ConnectDevicePageBody> {
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
), ),
// DeviceTile( Offstage(
// onPressed: () => Navigator.of(context).push( offstage: !longWait,
// MaterialPageRoute<void>( child: Padding(
// builder: (BuildContext context) => DebugDevicePage(), padding: EdgeInsets.only(left: 20, right: 20, bottom: 20),
// ), child: Text(S.of(context).if_you_dont_see_your_device,
// ), style: TextStyle(
// title: "Debug Ledger", fontSize: 16,
// leading: imageLedger, fontWeight: FontWeight.w500,
// ), color: Theme.of(context)
.extension<CakeTextTheme>()!
.titleColor),
textAlign: TextAlign.center,
),
),
),
Observer( Observer(
builder: (_) => Offstage( builder: (_) => Offstage(
offstage: widget.ledgerVM.bleIsEnabled, offstage: widget.ledgerVM.bleIsEnabled,

View file

@ -56,9 +56,8 @@ class _RestoreOptionsBodyState extends State<_RestoreOptionsBody> {
} }
if (isMoneroOnly) { if (isMoneroOnly) {
// return DeviceConnectionType.supportedConnectionTypes(WalletType.monero, Platform.isIOS) return DeviceConnectionType.supportedConnectionTypes(WalletType.monero, Platform.isIOS)
// .isNotEmpty; .isNotEmpty;
return false;
} }
return true; return true;

View file

@ -580,7 +580,10 @@ class SendPage extends BasePage {
alertTitle: S.of(context).proceed_on_device, alertTitle: S.of(context).proceed_on_device,
alertContent: S.of(context).proceed_on_device_description, alertContent: S.of(context).proceed_on_device_description,
buttonText: S.of(context).cancel, buttonText: S.of(context).cancel,
buttonAction: () => Navigator.of(context).pop()); buttonAction: () {
sendViewModel.state = InitialExecutionState();
Navigator.of(context).pop();
});
}); });
}); });
} }

View file

@ -422,8 +422,9 @@ class WalletListBodyState extends State<WalletListBody> {
if (!isAuthenticatedSuccessfully) return; if (!isAuthenticatedSuccessfully) return;
try { try {
if (widget.walletListViewModel final requireHardwareWalletConnection = widget.walletListViewModel
.requireHardwareWalletConnection(wallet)) { .requireHardwareWalletConnection(wallet);
if (requireHardwareWalletConnection) {
await Navigator.of(context).pushNamed( await Navigator.of(context).pushNamed(
Routes.connectDevices, Routes.connectDevices,
arguments: ConnectDevicePageParams( arguments: ConnectDevicePageParams(
@ -445,8 +446,6 @@ class WalletListBodyState extends State<WalletListBody> {
); );
} }
changeProcessText( changeProcessText(
S.of(context).wallet_list_loading_wallet(wallet.name)); S.of(context).wallet_list_loading_wallet(wallet.name));
await widget.walletListViewModel.loadWallet(wallet); await widget.walletListViewModel.loadWallet(wallet);
@ -456,6 +455,9 @@ class WalletListBodyState extends State<WalletListBody> {
if (responsiveLayoutUtil.shouldRenderMobileUI) { if (responsiveLayoutUtil.shouldRenderMobileUI) {
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
if (this.mounted) { if (this.mounted) {
if (requireHardwareWalletConnection) {
Navigator.of(context).pop();
}
widget.onWalletLoaded.call(context); widget.onWalletLoaded.call(context);
} }
}); });

View file

@ -4,7 +4,7 @@ part 'authentication_store.g.dart';
class AuthenticationStore = AuthenticationStoreBase with _$AuthenticationStore; class AuthenticationStore = AuthenticationStoreBase with _$AuthenticationStore;
enum AuthenticationState { uninitialized, installed, allowed, _reset } enum AuthenticationState { uninitialized, installed, allowed, allowedCreate, _reset }
abstract class AuthenticationStoreBase with Store { abstract class AuthenticationStoreBase with Store {
AuthenticationStoreBase() : state = AuthenticationState.uninitialized; AuthenticationStoreBase() : state = AuthenticationState.uninitialized;
@ -23,4 +23,10 @@ abstract class AuthenticationStoreBase with Store {
state = AuthenticationState._reset; state = AuthenticationState._reset;
state = AuthenticationState.allowed; state = AuthenticationState.allowed;
} }
@action
void allowedCreate() {
state = AuthenticationState._reset;
state = AuthenticationState.allowedCreate;
}
} }

View file

@ -4,14 +4,18 @@ import 'dart:io';
import 'package:cake_wallet/bitcoin/bitcoin.dart'; import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cake_wallet/ethereum/ethereum.dart'; import 'package:cake_wallet/ethereum/ethereum.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/main.dart';
import 'package:cake_wallet/monero/monero.dart'; import 'package:cake_wallet/monero/monero.dart';
import 'package:cake_wallet/polygon/polygon.dart'; import 'package:cake_wallet/polygon/polygon.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/connect_device/connect_device_page.dart';
import 'package:cake_wallet/utils/device_info.dart'; import 'package:cake_wallet/utils/device_info.dart';
import 'package:cake_wallet/wallet_type_utils.dart'; import 'package:cake_wallet/wallet_type_utils.dart';
import 'package:cw_core/hardware/device_connection_type.dart'; import 'package:cw_core/hardware/device_connection_type.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
import 'package:flutter/widgets.dart';
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart' as sdk; import 'package:ledger_flutter_plus/ledger_flutter_plus.dart' as sdk;
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
@ -59,7 +63,8 @@ abstract class LedgerViewModelBase with Store {
bool _bleIsInitialized = false; bool _bleIsInitialized = false;
Future<void> _initBLE() async { Future<void> _initBLE() async {
if (bleIsEnabled && !_bleIsInitialized) { if (bleIsEnabled && !_bleIsInitialized) {
ledgerPlusBLE = sdk.LedgerInterface.ble(onPermissionRequest: (_) async { ledgerPlusBLE = sdk.LedgerInterface.ble(
onPermissionRequest: (_) async {
Map<Permission, PermissionStatus> statuses = await [ Map<Permission, PermissionStatus> statuses = await [
Permission.bluetoothScan, Permission.bluetoothScan,
Permission.bluetoothConnect, Permission.bluetoothConnect,
@ -67,7 +72,9 @@ abstract class LedgerViewModelBase with Store {
].request(); ].request();
return statuses.values.where((status) => status.isDenied).isEmpty; return statuses.values.where((status) => status.isDenied).isEmpty;
}); },
bleOptions:
sdk.BluetoothOptions(maxScanDuration: Duration(minutes: 5)));
_bleIsInitialized = true; _bleIsInitialized = true;
} }
} }
@ -84,16 +91,26 @@ abstract class LedgerViewModelBase with Store {
Stream<sdk.LedgerDevice> scanForUsbDevices() => ledgerPlusUSB.scan(); Stream<sdk.LedgerDevice> scanForUsbDevices() => ledgerPlusUSB.scan();
Future<void> stopScanning() async {
await ledgerPlusBLE.stopScanning();
if (!Platform.isIOS) {
await ledgerPlusUSB.stopScanning();
}
}
Future<void> connectLedger(sdk.LedgerDevice device, WalletType type) async { Future<void> connectLedger(sdk.LedgerDevice device, WalletType type) async {
if (isConnected) { if (isConnected) {
try { try {
await _connection!.disconnect(); await _connectionChangeListener?.cancel();
_connectionChangeListener = null;
await _connection!.disconnect().catchError((_) {});
} catch (_) {} } catch (_) {}
} }
final ledger = device.connectionType == sdk.ConnectionType.ble final ledger = device.connectionType == sdk.ConnectionType.ble
? ledgerPlusBLE ? ledgerPlusBLE
: ledgerPlusUSB; : ledgerPlusUSB;
if (_connectionChangeListener == null) { if (_connectionChangeListener == null) {
_connectionChangeListener = ledger.deviceStateChanges.listen((event) { _connectionChangeListener = ledger.deviceStateChanges.listen((event) {
printV('Ledger Device State Changed: $event'); printV('Ledger Device State Changed: $event');
@ -101,6 +118,18 @@ abstract class LedgerViewModelBase with Store {
_connection = null; _connection = null;
if (type == WalletType.monero) { if (type == WalletType.monero) {
monero!.resetLedgerConnection(); monero!.resetLedgerConnection();
Navigator.of( navigatorKey.currentContext!).pushNamed(
Routes.connectDevices,
arguments: ConnectDevicePageParams(
walletType: WalletType.monero,
allowChangeWallet: true,
isReconnect: true,
onConnectDevice: (context, ledgerVM) async {
Navigator.of(context).pop();
},
),
);
} }
} }
}); });

View file

@ -8,7 +8,6 @@ import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/nano/nano.dart'; import 'package:cake_wallet/nano/nano.dart';
import 'package:cake_wallet/store/app_store.dart'; import 'package:cake_wallet/store/app_store.dart';
import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/view_model/restore/restore_mode.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/pathForWallet.dart'; import 'package:cw_core/pathForWallet.dart';
@ -114,7 +113,7 @@ abstract class WalletCreationVMBase with Store {
await _walletInfoSource.add(walletInfo); await _walletInfoSource.add(walletInfo);
await _appStore.changeCurrentWallet(wallet); await _appStore.changeCurrentWallet(wallet);
getIt.get<BackgroundTasks>().registerSyncTask(); getIt.get<BackgroundTasks>().registerSyncTask();
_appStore.authenticationStore.allowed(); _appStore.authenticationStore.allowedCreate();
state = ExecutedSuccessfullyState(); state = ExecutedSuccessfullyState();
} catch (e, s) { } catch (e, s) {
printV("error: $e"); printV("error: $e");

View file

@ -355,6 +355,7 @@
"how_to_use": " ﻞﻤﻌﺘﺴﺗ ﻒﻴﻛ", "how_to_use": " ﻞﻤﻌﺘﺴﺗ ﻒﻴﻛ",
"how_to_use_card": "كيفية استخدام هذه البطاقة", "how_to_use_card": "كيفية استخدام هذه البطاقة",
"id": "رقم المعرف:", "id": "رقم المعرف:",
"if_you_dont_see_your_device": "إذا كنت لا ترى جهازك أعلاه ، فيرجى التأكد من أن دفتر الأستاذ الخاص بك مستيقظًا ومؤمنًا!",
"ignor": "تجاهل", "ignor": "تجاهل",
"import": "ﺩﺭﻮﺘﺴﻳ", "import": "ﺩﺭﻮﺘﺴﻳ",
"importNFTs": "NFTs ﺩﺍﺮﻴﺘﺳﺍ", "importNFTs": "NFTs ﺩﺍﺮﻴﺘﺳﺍ",
@ -538,6 +539,7 @@
"recipient_address": "عنوان المستلم", "recipient_address": "عنوان المستلم",
"reconnect": "أعد الاتصال", "reconnect": "أعد الاتصال",
"reconnect_alert_text": "هل أنت متأكد من رغبتك في إعادة الاتصال؟", "reconnect_alert_text": "هل أنت متأكد من رغبتك في إعادة الاتصال؟",
"reconnect_your_hardware_wallet": "أعد توصيل محفظة الأجهزة الخاصة بك",
"reconnection": "إعادة الاتصال", "reconnection": "إعادة الاتصال",
"red_dark_theme": "موضوع الظلام الأحمر", "red_dark_theme": "موضوع الظلام الأحمر",
"red_light_theme": "موضوع الضوء الأحمر", "red_light_theme": "موضوع الضوء الأحمر",

View file

@ -355,6 +355,7 @@
"how_to_use": "Как да използвам", "how_to_use": "Как да използвам",
"how_to_use_card": "Как се ползва тази карта", "how_to_use_card": "Как се ползва тази карта",
"id": "ID: ", "id": "ID: ",
"if_you_dont_see_your_device": "Ако не виждате устройството си по -горе, моля, уверете се, че вашата книга е будна и отключена!",
"ignor": "Игнориране", "ignor": "Игнориране",
"import": "Импортиране", "import": "Импортиране",
"importNFTs": "Импортирайте NFT", "importNFTs": "Импортирайте NFT",
@ -538,6 +539,7 @@
"recipient_address": "Адрес на получател", "recipient_address": "Адрес на получател",
"reconnect": "Reconnect", "reconnect": "Reconnect",
"reconnect_alert_text": "Сигурни ли сте, че искате да се свържете отново?", "reconnect_alert_text": "Сигурни ли сте, че искате да се свържете отново?",
"reconnect_your_hardware_wallet": "Свържете отново хардуерния си портфейл",
"reconnection": "Свързване отново", "reconnection": "Свързване отново",
"red_dark_theme": "Червена тъмна тема", "red_dark_theme": "Червена тъмна тема",
"red_light_theme": "Тема на червената светлина", "red_light_theme": "Тема на червената светлина",

View file

@ -355,6 +355,7 @@
"how_to_use": "Jak používat", "how_to_use": "Jak používat",
"how_to_use_card": "Jak použít tuto kartu", "how_to_use_card": "Jak použít tuto kartu",
"id": "ID: ", "id": "ID: ",
"if_you_dont_see_your_device": "Pokud vaše zařízení nevidíte výše, ujistěte se, že vaše kniha je vzhůru a odemknutá!",
"ignor": "Ignorovat", "ignor": "Ignorovat",
"import": "Import", "import": "Import",
"importNFTs": "Importujte NFT", "importNFTs": "Importujte NFT",
@ -538,6 +539,7 @@
"recipient_address": "Adresa příjemce", "recipient_address": "Adresa příjemce",
"reconnect": "Znovu připojit", "reconnect": "Znovu připojit",
"reconnect_alert_text": "Opravdu se chcete znovu připojit?", "reconnect_alert_text": "Opravdu se chcete znovu připojit?",
"reconnect_your_hardware_wallet": "Znovu připojte svou hardwarovou peněženku",
"reconnection": "Znovu připojit", "reconnection": "Znovu připojit",
"red_dark_theme": "Červené temné téma", "red_dark_theme": "Červené temné téma",
"red_light_theme": "Téma červeného světla", "red_light_theme": "Téma červeného světla",

View file

@ -355,6 +355,7 @@
"how_to_use": "Wie benutzt man", "how_to_use": "Wie benutzt man",
"how_to_use_card": "Wie man diese Karte benutzt", "how_to_use_card": "Wie man diese Karte benutzt",
"id": "ID: ", "id": "ID: ",
"if_you_dont_see_your_device": "Wenn Sie Ihr Gerät nicht sehen, stellen Sie bitte sicher, dass Ihr Ledger an und entsperrt ist!",
"ignor": "Ignorieren", "ignor": "Ignorieren",
"import": "Importieren", "import": "Importieren",
"importNFTs": "NFTs importieren", "importNFTs": "NFTs importieren",
@ -539,6 +540,7 @@
"recipient_address": "Empfängeradresse", "recipient_address": "Empfängeradresse",
"reconnect": "Erneut verbinden", "reconnect": "Erneut verbinden",
"reconnect_alert_text": "Sind Sie sicher, dass Sie sich neu verbinden möchten?", "reconnect_alert_text": "Sind Sie sicher, dass Sie sich neu verbinden möchten?",
"reconnect_your_hardware_wallet": "Hardware-Wallet neu verbinden",
"reconnection": "Neu verbinden", "reconnection": "Neu verbinden",
"red_dark_theme": "Red Dark Thema", "red_dark_theme": "Red Dark Thema",
"red_light_theme": "Red Light Thema", "red_light_theme": "Red Light Thema",

View file

@ -355,6 +355,7 @@
"how_to_use": "How to use", "how_to_use": "How to use",
"how_to_use_card": "How to use this card", "how_to_use_card": "How to use this card",
"id": "ID: ", "id": "ID: ",
"if_you_dont_see_your_device": "If you don't see your device above, please be sure your Ledger is awake and unlocked!",
"ignor": "Ignore", "ignor": "Ignore",
"import": "Import", "import": "Import",
"importNFTs": "Import NFTs", "importNFTs": "Import NFTs",
@ -538,6 +539,7 @@
"recipient_address": "Recipient address", "recipient_address": "Recipient address",
"reconnect": "Reconnect", "reconnect": "Reconnect",
"reconnect_alert_text": "Are you sure you want to reconnect?", "reconnect_alert_text": "Are you sure you want to reconnect?",
"reconnect_your_hardware_wallet": "Reconnect your Hardware Wallet",
"reconnection": "Reconnection", "reconnection": "Reconnection",
"red_dark_theme": "Red Dark Theme", "red_dark_theme": "Red Dark Theme",
"red_light_theme": "Red Light Theme", "red_light_theme": "Red Light Theme",

View file

@ -355,6 +355,7 @@
"how_to_use": "Cómo utilizar", "how_to_use": "Cómo utilizar",
"how_to_use_card": "Cómo usar esta tarjeta", "how_to_use_card": "Cómo usar esta tarjeta",
"id": "ID: ", "id": "ID: ",
"if_you_dont_see_your_device": "Si no ve su dispositivo arriba, ¡asegúrese de que su libro mayor esté despierto y desbloqueado!",
"ignor": "Pasar por alto", "ignor": "Pasar por alto",
"import": "Importar", "import": "Importar",
"importNFTs": "Importar NFT", "importNFTs": "Importar NFT",
@ -539,6 +540,7 @@
"recipient_address": "Dirección del receptor", "recipient_address": "Dirección del receptor",
"reconnect": "Volver a conectar", "reconnect": "Volver a conectar",
"reconnect_alert_text": "¿Estás seguro de reconectar?", "reconnect_alert_text": "¿Estás seguro de reconectar?",
"reconnect_your_hardware_wallet": "Vuelva a conectar su billetera de hardware",
"reconnection": "Reconexión", "reconnection": "Reconexión",
"red_dark_theme": "Tema rojo oscuro", "red_dark_theme": "Tema rojo oscuro",
"red_light_theme": "Tema de la luz roja", "red_light_theme": "Tema de la luz roja",

View file

@ -355,6 +355,7 @@
"how_to_use": "Comment utiliser", "how_to_use": "Comment utiliser",
"how_to_use_card": "Comment utiliser cette carte", "how_to_use_card": "Comment utiliser cette carte",
"id": "ID : ", "id": "ID : ",
"if_you_dont_see_your_device": "Si vous ne voyez pas votre appareil ci-dessus, assurez-vous que votre grand livre est éveillé et déverrouillé!",
"ignor": "Ignorer", "ignor": "Ignorer",
"import": "Importer", "import": "Importer",
"importNFTs": "Importer des NFT", "importNFTs": "Importer des NFT",
@ -538,6 +539,7 @@
"recipient_address": "Adresse bénéficiaire", "recipient_address": "Adresse bénéficiaire",
"reconnect": "Reconnecter", "reconnect": "Reconnecter",
"reconnect_alert_text": "Êtes vous certain de vouloir vous reconnecter ?", "reconnect_alert_text": "Êtes vous certain de vouloir vous reconnecter ?",
"reconnect_your_hardware_wallet": "Reconnectez votre portefeuille matériel",
"reconnection": "Reconnexion", "reconnection": "Reconnexion",
"red_dark_theme": "Thème rouge sombre", "red_dark_theme": "Thème rouge sombre",
"red_light_theme": "Thème rouge clair", "red_light_theme": "Thème rouge clair",

View file

@ -355,6 +355,7 @@
"how_to_use": "Yadda ake amfani da shi", "how_to_use": "Yadda ake amfani da shi",
"how_to_use_card": "Yadda ake amfani da wannan kati", "how_to_use_card": "Yadda ake amfani da wannan kati",
"id": "ID:", "id": "ID:",
"if_you_dont_see_your_device": "Idan baku ga na'urarka da ke sama ba, da fatan za a tabbata Ledger dinku yana farkawa kuma a buɗe!",
"ignor": "Yi watsi da shi", "ignor": "Yi watsi da shi",
"import": "Shigo da", "import": "Shigo da",
"importNFTs": "Shigo da NFTs", "importNFTs": "Shigo da NFTs",
@ -540,6 +541,7 @@
"recipient_address": "Adireshin mai karɓa", "recipient_address": "Adireshin mai karɓa",
"reconnect": "Sake haɗawa", "reconnect": "Sake haɗawa",
"reconnect_alert_text": "Shin kun tabbata kuna son sake haɗawa?", "reconnect_alert_text": "Shin kun tabbata kuna son sake haɗawa?",
"reconnect_your_hardware_wallet": "Sake kunnawa kayan aiki",
"reconnection": "Sake haɗawa", "reconnection": "Sake haɗawa",
"red_dark_theme": "Ja duhu taken", "red_dark_theme": "Ja duhu taken",
"red_light_theme": "Ja mai haske", "red_light_theme": "Ja mai haske",

View file

@ -355,6 +355,7 @@
"how_to_use": "का उपयोग कैसे करें", "how_to_use": "का उपयोग कैसे करें",
"how_to_use_card": "इस कार्ड का उपयोग कैसे करें", "how_to_use_card": "इस कार्ड का उपयोग कैसे करें",
"id": "ID: ", "id": "ID: ",
"if_you_dont_see_your_device": "यदि आप अपने डिवाइस को ऊपर नहीं देखते हैं, तो कृपया सुनिश्चित करें कि आपका लेजर जागृत और अनलॉक हो गया है!",
"ignor": "नज़रअंदाज़ करना", "ignor": "नज़रअंदाज़ करना",
"import": "आयात", "import": "आयात",
"importNFTs": "एनएफटी आयात करें", "importNFTs": "एनएफटी आयात करें",
@ -540,6 +541,7 @@
"recipient_address": "प्राप्तकर्ता का पता", "recipient_address": "प्राप्तकर्ता का पता",
"reconnect": "रिकनेक्ट", "reconnect": "रिकनेक्ट",
"reconnect_alert_text": "क्या आप पुन: कनेक्ट होना सुनिश्चित करते हैं?", "reconnect_alert_text": "क्या आप पुन: कनेक्ट होना सुनिश्चित करते हैं?",
"reconnect_your_hardware_wallet": "अपने हार्डवेयर वॉलेट को फिर से कनेक्ट करें",
"reconnection": "पुनर्संयोजन", "reconnection": "पुनर्संयोजन",
"red_dark_theme": "लाल डार्क थीम", "red_dark_theme": "लाल डार्क थीम",
"red_light_theme": "लाल प्रकाश थीम", "red_light_theme": "लाल प्रकाश थीम",

View file

@ -355,6 +355,7 @@
"how_to_use": "Kako koristiti", "how_to_use": "Kako koristiti",
"how_to_use_card": "Kako koristiti ovu karticu", "how_to_use_card": "Kako koristiti ovu karticu",
"id": "ID: ", "id": "ID: ",
"if_you_dont_see_your_device": "Ako svoj uređaj ne vidite gore, budite sigurni da je vaša knjiga budna i otključana!",
"ignor": "Zanemariti", "ignor": "Zanemariti",
"import": "Uvoz", "import": "Uvoz",
"importNFTs": "Uvoz NFT-ova", "importNFTs": "Uvoz NFT-ova",
@ -538,6 +539,7 @@
"recipient_address": "Primateljeva adresa", "recipient_address": "Primateljeva adresa",
"reconnect": "Ponovno povezivanje", "reconnect": "Ponovno povezivanje",
"reconnect_alert_text": "Jeste li sigurni da se želite ponovno povezati?", "reconnect_alert_text": "Jeste li sigurni da se želite ponovno povezati?",
"reconnect_your_hardware_wallet": "Ponovno spojite svoj hardverski novčanik",
"reconnection": "Ponovno povezivanje", "reconnection": "Ponovno povezivanje",
"red_dark_theme": "Crvena tamna tema", "red_dark_theme": "Crvena tamna tema",
"red_light_theme": "Tema crvenog svjetla", "red_light_theme": "Tema crvenog svjetla",

View file

@ -355,6 +355,7 @@
"how_to_use": "Ինչպես օգտագործել", "how_to_use": "Ինչպես օգտագործել",
"how_to_use_card": "Ինչպես օգտագործել այս քարտը", "how_to_use_card": "Ինչպես օգտագործել այս քարտը",
"id": "ID: ", "id": "ID: ",
"if_you_dont_see_your_device": "Եթե ​​ձեր սարքը վերեւում չեք տեսնում, համոզվեք, որ ձեր Ledger- ը արթուն է եւ բացված:",
"ignor": "Անտեսել", "ignor": "Անտեսել",
"import": "Ներմուծել", "import": "Ներմուծել",
"importNFTs": "Ներմուծել NFT-ներ", "importNFTs": "Ներմուծել NFT-ներ",
@ -538,6 +539,7 @@
"recipient_address": "Ստացողի հասցե", "recipient_address": "Ստացողի հասցե",
"reconnect": "Վերակապվել", "reconnect": "Վերակապվել",
"reconnect_alert_text": "Դուք վստահ եք, որ ուզում եք վերակապվել?", "reconnect_alert_text": "Դուք վստահ եք, որ ուզում եք վերակապվել?",
"reconnect_your_hardware_wallet": "Միացրեք ձեր ապարատային դրամապանակը",
"reconnection": "Վերակապում", "reconnection": "Վերակապում",
"red_dark_theme": "Կարմիր մութ տեսք", "red_dark_theme": "Կարմիր մութ տեսք",
"red_light_theme": "Կարմիր պայծառ տեսք", "red_light_theme": "Կարմիր պայծառ տեսք",

View file

@ -355,6 +355,7 @@
"how_to_use": "Cara Penggunaan", "how_to_use": "Cara Penggunaan",
"how_to_use_card": "Bagaimana menggunakan kartu ini", "how_to_use_card": "Bagaimana menggunakan kartu ini",
"id": "ID: ", "id": "ID: ",
"if_you_dont_see_your_device": "Jika Anda tidak melihat perangkat Anda di atas, pastikan buku besar Anda terjaga dan tidak terkunci!",
"ignor": "Abaikan", "ignor": "Abaikan",
"import": "Impor", "import": "Impor",
"importNFTs": "Impor NFT", "importNFTs": "Impor NFT",
@ -540,6 +541,7 @@
"recipient_address": "Alamat penerima", "recipient_address": "Alamat penerima",
"reconnect": "Sambungkan kembali", "reconnect": "Sambungkan kembali",
"reconnect_alert_text": "Apakah Anda yakin ingin menyambungkan kembali?", "reconnect_alert_text": "Apakah Anda yakin ingin menyambungkan kembali?",
"reconnect_your_hardware_wallet": "Hubungkan kembali dompet perangkat keras Anda",
"reconnection": "Koneksi kembali", "reconnection": "Koneksi kembali",
"red_dark_theme": "Tema gelap merah", "red_dark_theme": "Tema gelap merah",
"red_light_theme": "Tema lampu merah", "red_light_theme": "Tema lampu merah",

View file

@ -356,6 +356,7 @@
"how_to_use": "Come usare", "how_to_use": "Come usare",
"how_to_use_card": "Come usare questa carta", "how_to_use_card": "Come usare questa carta",
"id": "ID: ", "id": "ID: ",
"if_you_dont_see_your_device": "Se non vedi il tuo dispositivo sopra, assicurati che il tuo libro mastro sia sveglio e sbloccato!",
"ignor": "Ignorare", "ignor": "Ignorare",
"import": "Importare", "import": "Importare",
"importNFTs": "Importa NFT", "importNFTs": "Importa NFT",
@ -540,6 +541,7 @@
"recipient_address": "Indirizzo di destinazione", "recipient_address": "Indirizzo di destinazione",
"reconnect": "Riconnetti", "reconnect": "Riconnetti",
"reconnect_alert_text": "Sei sicuro di volerti riconnettere?", "reconnect_alert_text": "Sei sicuro di volerti riconnettere?",
"reconnect_your_hardware_wallet": "Ricollega il tuo portafoglio hardware",
"reconnection": "Riconnessione", "reconnection": "Riconnessione",
"red_dark_theme": "Red Dark Theme", "red_dark_theme": "Red Dark Theme",
"red_light_theme": "Tema della luce rossa", "red_light_theme": "Tema della luce rossa",

View file

@ -356,6 +356,7 @@
"how_to_use": "使い方", "how_to_use": "使い方",
"how_to_use_card": "このカードの使用方法", "how_to_use_card": "このカードの使用方法",
"id": "ID: ", "id": "ID: ",
"if_you_dont_see_your_device": "上記のデバイスが表示されない場合は、元帳が目を覚ましてロック解除されていることを確認してください!",
"ignor": "無視", "ignor": "無視",
"import": "輸入", "import": "輸入",
"importNFTs": "NFTのインポート", "importNFTs": "NFTのインポート",
@ -539,6 +540,7 @@
"recipient_address": "受信者のアドレス", "recipient_address": "受信者のアドレス",
"reconnect": "再接続", "reconnect": "再接続",
"reconnect_alert_text": "再接続しますか?", "reconnect_alert_text": "再接続しますか?",
"reconnect_your_hardware_wallet": "ハードウェアウォレットを再接続します",
"reconnection": "再接続", "reconnection": "再接続",
"red_dark_theme": "赤い暗いテーマ", "red_dark_theme": "赤い暗いテーマ",
"red_light_theme": "赤色光のテーマ", "red_light_theme": "赤色光のテーマ",

View file

@ -355,6 +355,7 @@
"how_to_use": "사용하는 방법", "how_to_use": "사용하는 방법",
"how_to_use_card": "이 카드를 사용하는 방법", "how_to_use_card": "이 카드를 사용하는 방법",
"id": "ID: ", "id": "ID: ",
"if_you_dont_see_your_device": "위의 장치가 표시되지 않으면 원장이 깨어 있고 잠금 해제되었는지 확인하십시오!",
"ignor": "무시하다", "ignor": "무시하다",
"import": "수입", "import": "수입",
"importNFTs": "NFT 가져오기", "importNFTs": "NFT 가져오기",
@ -502,8 +503,8 @@
"placeholder_transactions": "거래가 여기에 표시됩니다", "placeholder_transactions": "거래가 여기에 표시됩니다",
"please_fill_totp": "다른 기기에 있는 8자리 코드를 입력하세요.", "please_fill_totp": "다른 기기에 있는 8자리 코드를 입력하세요.",
"please_make_selection": "아래에서 선택하십시오 지갑 만들기 또는 복구.", "please_make_selection": "아래에서 선택하십시오 지갑 만들기 또는 복구.",
"please_reference_document": "자세한 내용은 아래 문서를 참조하십시오.",
"Please_reference_document": "자세한 내용은 아래 문서를 참조하십시오.", "Please_reference_document": "자세한 내용은 아래 문서를 참조하십시오.",
"please_reference_document": "자세한 내용은 아래 문서를 참조하십시오.",
"please_select": "선택 해주세요:", "please_select": "선택 해주세요:",
"please_select_backup_file": "백업 파일을 선택하고 백업 암호를 입력하십시오.", "please_select_backup_file": "백업 파일을 선택하고 백업 암호를 입력하십시오.",
"please_try_to_connect_to_another_node": "다른 노드에 연결을 시도하십시오", "please_try_to_connect_to_another_node": "다른 노드에 연결을 시도하십시오",
@ -539,6 +540,7 @@
"recipient_address": "받는 사람 주소", "recipient_address": "받는 사람 주소",
"reconnect": "다시 연결", "reconnect": "다시 연결",
"reconnect_alert_text": "다시 연결 하시겠습니까?", "reconnect_alert_text": "다시 연결 하시겠습니까?",
"reconnect_your_hardware_wallet": "하드웨어 지갑을 다시 연결하십시오",
"reconnection": "재 연결", "reconnection": "재 연결",
"red_dark_theme": "빨간 어두운 테마", "red_dark_theme": "빨간 어두운 테마",
"red_light_theme": "빨간불 테마", "red_light_theme": "빨간불 테마",

View file

@ -355,6 +355,7 @@
"how_to_use": "အသုံးပြုနည်း", "how_to_use": "အသုံးပြုနည်း",
"how_to_use_card": "ဒီကတ်ကို ဘယ်လိုသုံးမလဲ။", "how_to_use_card": "ဒီကတ်ကို ဘယ်လိုသုံးမလဲ။",
"id": "ID:", "id": "ID:",
"if_you_dont_see_your_device": "သင်၏စက်ကိုအထက်တွင်မတွေ့ပါကသင်၏ Ledger သည်နိုးလာပြီးသော့ဖွင့်နေသည်ကိုသေချာပါစေ။",
"ignor": "လျစ်လျူရှုပါ။", "ignor": "လျစ်လျူရှုပါ။",
"import": "သွင်းကုန်", "import": "သွင်းကုန်",
"importNFTs": "NFTs များကို တင်သွင်းပါ။", "importNFTs": "NFTs များကို တင်သွင်းပါ။",
@ -538,6 +539,7 @@
"recipient_address": "လက်ခံသူလိပ်စာ", "recipient_address": "လက်ခံသူလိပ်စာ",
"reconnect": "ပြန်လည်ချိတ်ဆက်ပါ။", "reconnect": "ပြန်လည်ချိတ်ဆက်ပါ။",
"reconnect_alert_text": "ပြန်လည်ချိတ်ဆက်လိုသည်မှာ သေချာပါသလား။ ?", "reconnect_alert_text": "ပြန်လည်ချိတ်ဆက်လိုသည်မှာ သေချာပါသလား။ ?",
"reconnect_your_hardware_wallet": "သင့်ရဲ့ hardware ပိုက်ဆံအိတ်ကိုပြန်လည်ချိတ်ဆက်ပါ",
"reconnection": "ပြန်လည်ချိတ်ဆက်မှု", "reconnection": "ပြန်လည်ချိတ်ဆက်မှု",
"red_dark_theme": "အနီရောင်မှောင်မိုက်ဆောင်ပုဒ်", "red_dark_theme": "အနီရောင်မှောင်မိုက်ဆောင်ပုဒ်",
"red_light_theme": "အနီရောင်အလင်းအကြောင်းအရာ", "red_light_theme": "အနီရောင်အလင်းအကြောင်းအရာ",

View file

@ -355,6 +355,7 @@
"how_to_use": "Hoe te gebruiken", "how_to_use": "Hoe te gebruiken",
"how_to_use_card": "Hoe deze kaart te gebruiken", "how_to_use_card": "Hoe deze kaart te gebruiken",
"id": "ID: ", "id": "ID: ",
"if_you_dont_see_your_device": "Als u uw apparaat hierboven niet ziet, zorg er dan voor dat uw grootboek wakker is en ontgrendeld is!",
"ignor": "Negeren", "ignor": "Negeren",
"import": "Importeren", "import": "Importeren",
"importNFTs": "NFT's importeren", "importNFTs": "NFT's importeren",
@ -538,6 +539,7 @@
"recipient_address": "Adres ontvanger", "recipient_address": "Adres ontvanger",
"reconnect": "Sluit", "reconnect": "Sluit",
"reconnect_alert_text": "Weet u zeker dat u opnieuw verbinding wilt maken?", "reconnect_alert_text": "Weet u zeker dat u opnieuw verbinding wilt maken?",
"reconnect_your_hardware_wallet": "Sluit uw hardware -portemonnee opnieuw aan",
"reconnection": "Reconnection", "reconnection": "Reconnection",
"red_dark_theme": "Rood donker thema", "red_dark_theme": "Rood donker thema",
"red_light_theme": "Rood licht thema", "red_light_theme": "Rood licht thema",

View file

@ -355,6 +355,7 @@
"how_to_use": "Jak używać", "how_to_use": "Jak używać",
"how_to_use_card": "Jak korzystać z tej karty?", "how_to_use_card": "Jak korzystać z tej karty?",
"id": "ID: ", "id": "ID: ",
"if_you_dont_see_your_device": "Jeśli nie widzisz swojego urządzenia powyżej, upewnij się, że Twoja księga nie śpi i odblokowana!",
"ignor": "Ignorować", "ignor": "Ignorować",
"import": "Import", "import": "Import",
"importNFTs": "Importuj NFT", "importNFTs": "Importuj NFT",
@ -538,6 +539,7 @@
"recipient_address": "Adres odbiorcy", "recipient_address": "Adres odbiorcy",
"reconnect": "Połącz ponownie", "reconnect": "Połącz ponownie",
"reconnect_alert_text": "Czy na pewno ponownie się ponownie połączysz?", "reconnect_alert_text": "Czy na pewno ponownie się ponownie połączysz?",
"reconnect_your_hardware_wallet": "Ponownie podłącz portfel sprzętowy",
"reconnection": "Ponowne łączenie", "reconnection": "Ponowne łączenie",
"red_dark_theme": "Czerwony Mroczny motyw", "red_dark_theme": "Czerwony Mroczny motyw",
"red_light_theme": "Motyw czerwony światło", "red_light_theme": "Motyw czerwony światło",

View file

@ -355,6 +355,7 @@
"how_to_use": "Como usar", "how_to_use": "Como usar",
"how_to_use_card": "Como usar este cartão", "how_to_use_card": "Como usar este cartão",
"id": "ID: ", "id": "ID: ",
"if_you_dont_see_your_device": "Se você não vê seu dispositivo acima, certifique -se de que seu livro esteja acordado e desbloqueado!",
"ignor": "Ignorar", "ignor": "Ignorar",
"import": "Importar", "import": "Importar",
"importNFTs": "Importar NFTs", "importNFTs": "Importar NFTs",
@ -540,6 +541,7 @@
"recipient_address": "Endereço do destinatário", "recipient_address": "Endereço do destinatário",
"reconnect": "Reconectar", "reconnect": "Reconectar",
"reconnect_alert_text": "Você tem certeza de que deseja reconectar?", "reconnect_alert_text": "Você tem certeza de que deseja reconectar?",
"reconnect_your_hardware_wallet": "Reconecte sua carteira de hardware",
"reconnection": "Reconectar", "reconnection": "Reconectar",
"red_dark_theme": "Tema escuro vermelho", "red_dark_theme": "Tema escuro vermelho",
"red_light_theme": "Tema da luz vermelha", "red_light_theme": "Tema da luz vermelha",

View file

@ -355,6 +355,7 @@
"how_to_use": "Как использовать", "how_to_use": "Как использовать",
"how_to_use_card": "Как использовать эту карту", "how_to_use_card": "Как использовать эту карту",
"id": "ID: ", "id": "ID: ",
"if_you_dont_see_your_device": "Если вы не видите свое устройство выше, пожалуйста, убедитесь, что ваша бухгалтерская книга бодрствует и разблокирована!",
"ignor": "Игнорировать", "ignor": "Игнорировать",
"import": "Импортировать", "import": "Импортировать",
"importNFTs": "Импортировать NFT", "importNFTs": "Импортировать NFT",
@ -539,6 +540,7 @@
"recipient_address": "Адрес получателя", "recipient_address": "Адрес получателя",
"reconnect": "Переподключиться", "reconnect": "Переподключиться",
"reconnect_alert_text": "Вы хотите переподключиться?", "reconnect_alert_text": "Вы хотите переподключиться?",
"reconnect_your_hardware_wallet": "Воссоедините свой аппаратный кошелек",
"reconnection": "Переподключение", "reconnection": "Переподключение",
"red_dark_theme": "Красная темная тема", "red_dark_theme": "Красная темная тема",
"red_light_theme": "Тема красного света", "red_light_theme": "Тема красного света",

View file

@ -355,6 +355,7 @@
"how_to_use": "วิธีใช้", "how_to_use": "วิธีใช้",
"how_to_use_card": "วิธีใช้บัตรนี้", "how_to_use_card": "วิธีใช้บัตรนี้",
"id": "ID: ", "id": "ID: ",
"if_you_dont_see_your_device": "หากคุณไม่เห็นอุปกรณ์ของคุณด้านบนโปรดตรวจสอบให้แน่ใจว่าบัญชีแยกประเภทของคุณตื่นและปลดล็อค!",
"ignor": "ละเว้น", "ignor": "ละเว้น",
"import": "นำเข้า", "import": "นำเข้า",
"importNFTs": "นำเข้า NFT", "importNFTs": "นำเข้า NFT",
@ -538,6 +539,7 @@
"recipient_address": "ที่อยู่ผู้รับ", "recipient_address": "ที่อยู่ผู้รับ",
"reconnect": "เชื่อมต่อใหม่", "reconnect": "เชื่อมต่อใหม่",
"reconnect_alert_text": "คุณแน่ใจหรือไม่ว่าต้องการเชื่อมต่อใหม่?", "reconnect_alert_text": "คุณแน่ใจหรือไม่ว่าต้องการเชื่อมต่อใหม่?",
"reconnect_your_hardware_wallet": "เชื่อมต่อกระเป๋าเงินฮาร์ดแวร์ของคุณอีกครั้ง",
"reconnection": "เชื่อมต่อใหม่", "reconnection": "เชื่อมต่อใหม่",
"red_dark_theme": "ธีมสีแดงเข้ม", "red_dark_theme": "ธีมสีแดงเข้ม",
"red_light_theme": "ธีมแสงสีแดง", "red_light_theme": "ธีมแสงสีแดง",

View file

@ -355,6 +355,7 @@
"how_to_use": "Paano gamitin", "how_to_use": "Paano gamitin",
"how_to_use_card": "Paano gamitin ang card na ito", "how_to_use_card": "Paano gamitin ang card na ito",
"id": "ID: ", "id": "ID: ",
"if_you_dont_see_your_device": "Kung hindi mo nakikita ang iyong aparato sa itaas, siguraduhin na ang iyong ledger ay gising at naka -lock!",
"ignor": "Huwag pansinin", "ignor": "Huwag pansinin",
"import": "Mag-import", "import": "Mag-import",
"importNFTs": "Mag-import ng mga NFT", "importNFTs": "Mag-import ng mga NFT",
@ -538,6 +539,7 @@
"recipient_address": "Address ng tatanggap", "recipient_address": "Address ng tatanggap",
"reconnect": "Kumonekta muli", "reconnect": "Kumonekta muli",
"reconnect_alert_text": "Sigurado ka bang gusto mong kumonekta uli?", "reconnect_alert_text": "Sigurado ka bang gusto mong kumonekta uli?",
"reconnect_your_hardware_wallet": "Ikonekta muli ang iyong wallet ng hardware",
"reconnection": "Muling pagkakakonekta", "reconnection": "Muling pagkakakonekta",
"red_dark_theme": "Red Dark Theme", "red_dark_theme": "Red Dark Theme",
"red_light_theme": "Red Light Theme", "red_light_theme": "Red Light Theme",

View file

@ -355,6 +355,7 @@
"how_to_use": "Nasıl kullanılır", "how_to_use": "Nasıl kullanılır",
"how_to_use_card": "Bu kart nasıl kullanılır", "how_to_use_card": "Bu kart nasıl kullanılır",
"id": "ID: ", "id": "ID: ",
"if_you_dont_see_your_device": "Cihazınızı yukarıda görmüyorsanız, lütfen defterinizin uyanık olduğundan ve kilidinin açıldığından emin olun!",
"ignor": "Yoksay", "ignor": "Yoksay",
"import": "İçe aktarmak", "import": "İçe aktarmak",
"importNFTs": "NFT'leri içe aktar", "importNFTs": "NFT'leri içe aktar",
@ -538,6 +539,7 @@
"recipient_address": "Alıcı adresi", "recipient_address": "Alıcı adresi",
"reconnect": "Yeniden Bağlan", "reconnect": "Yeniden Bağlan",
"reconnect_alert_text": "Yeniden bağlanmak istediğinden emin misin?", "reconnect_alert_text": "Yeniden bağlanmak istediğinden emin misin?",
"reconnect_your_hardware_wallet": "Donanım cüzdanınızı yeniden bağlayın",
"reconnection": "Yeniden bağlantı", "reconnection": "Yeniden bağlantı",
"red_dark_theme": "Kırmızı Karanlık Tema", "red_dark_theme": "Kırmızı Karanlık Tema",
"red_light_theme": "Kırmızıık Teması", "red_light_theme": "Kırmızıık Teması",

View file

@ -355,6 +355,7 @@
"how_to_use": "Як використовувати", "how_to_use": "Як використовувати",
"how_to_use_card": "Як використовувати цю картку", "how_to_use_card": "Як використовувати цю картку",
"id": "ID: ", "id": "ID: ",
"if_you_dont_see_your_device": "Якщо ви не бачите свого пристрою вище, будь ласка, переконайтеся, що ваша книга прокинеться і розблокована!",
"ignor": "Ігнорувати", "ignor": "Ігнорувати",
"import": "Імпорт", "import": "Імпорт",
"importNFTs": "Імпорт NFT", "importNFTs": "Імпорт NFT",
@ -538,6 +539,7 @@
"recipient_address": "Адреса одержувача", "recipient_address": "Адреса одержувача",
"reconnect": "Перепідключитися", "reconnect": "Перепідключитися",
"reconnect_alert_text": "Ви хочете перепідключитися?", "reconnect_alert_text": "Ви хочете перепідключитися?",
"reconnect_your_hardware_wallet": "Повторно підключіть свій апаратний гаманець",
"reconnection": "Перепідключення", "reconnection": "Перепідключення",
"red_dark_theme": "Червона темна тема", "red_dark_theme": "Червона темна тема",
"red_light_theme": "Тема червоного світла", "red_light_theme": "Тема червоного світла",

View file

@ -355,6 +355,7 @@
"how_to_use": " ﮧﻘﯾﺮﻃ ﺎﮐ ﮯﻧﺮﮐ ﻝﺎﻤﻌﺘﺳﺍ", "how_to_use": " ﮧﻘﯾﺮﻃ ﺎﮐ ﮯﻧﺮﮐ ﻝﺎﻤﻌﺘﺳﺍ",
"how_to_use_card": "اس کارڈ کو استعمال کرنے کا طریقہ", "how_to_use_card": "اس کارڈ کو استعمال کرنے کا طریقہ",
"id": "ID:", "id": "ID:",
"if_you_dont_see_your_device": "اگر آپ اوپر اپنا آلہ نہیں دیکھتے ہیں تو ، براہ کرم یقینی بنائیں کہ آپ کا لیجر بیدار اور غیر مقفل ہے!",
"ignor": "نظر انداز کرنا", "ignor": "نظر انداز کرنا",
"import": " ۔ﮟﯾﺮﮐ ﺪﻣﺁﺭﺩ", "import": " ۔ﮟﯾﺮﮐ ﺪﻣﺁﺭﺩ",
"importNFTs": "NFTs ۔ﮟﯾﺮﮐ ﺪﻣﺁﺭﺩ", "importNFTs": "NFTs ۔ﮟﯾﺮﮐ ﺪﻣﺁﺭﺩ",
@ -540,6 +541,7 @@
"recipient_address": "وصول کنندہ کا پتہ", "recipient_address": "وصول کنندہ کا پتہ",
"reconnect": "دوبارہ جڑیں۔", "reconnect": "دوبارہ جڑیں۔",
"reconnect_alert_text": "کیا آپ واقعی دوبارہ جڑنا چاہتے ہیں؟", "reconnect_alert_text": "کیا آپ واقعی دوبارہ جڑنا چاہتے ہیں؟",
"reconnect_your_hardware_wallet": "اپنے ہارڈ ویئر پرس کو دوبارہ مربوط کریں",
"reconnection": "دوبارہ رابطہ", "reconnection": "دوبارہ رابطہ",
"red_dark_theme": "ریڈ ڈارک تھیم", "red_dark_theme": "ریڈ ڈارک تھیم",
"red_light_theme": "ریڈ لائٹ تھیم", "red_light_theme": "ریڈ لائٹ تھیم",

View file

@ -354,6 +354,7 @@
"how_to_use": "Cách sử dụng", "how_to_use": "Cách sử dụng",
"how_to_use_card": "Cách sử dụng thẻ này", "how_to_use_card": "Cách sử dụng thẻ này",
"id": "ID: ", "id": "ID: ",
"if_you_dont_see_your_device": "Nếu bạn không thấy thiết bị của mình ở trên, xin hãy chắc chắn rằng sổ cái của bạn đã tỉnh táo và mở khóa!",
"ignor": "Bỏ qua", "ignor": "Bỏ qua",
"import": "Nhập", "import": "Nhập",
"importNFTs": "Nhập NFT", "importNFTs": "Nhập NFT",
@ -537,6 +538,7 @@
"recipient_address": "Địa chỉ người nhận", "recipient_address": "Địa chỉ người nhận",
"reconnect": "Kết nối lại", "reconnect": "Kết nối lại",
"reconnect_alert_text": "Bạn có chắc chắn muốn kết nối lại không?", "reconnect_alert_text": "Bạn có chắc chắn muốn kết nối lại không?",
"reconnect_your_hardware_wallet": "Kết nối lại ví phần cứng của bạn",
"reconnection": "Kết nối lại", "reconnection": "Kết nối lại",
"red_dark_theme": "Chủ đề tối đỏ", "red_dark_theme": "Chủ đề tối đỏ",
"red_light_theme": "Chủ đề sáng đỏ", "red_light_theme": "Chủ đề sáng đỏ",

View file

@ -356,6 +356,7 @@
"how_to_use": "Bawo ni lati lo", "how_to_use": "Bawo ni lati lo",
"how_to_use_card": "Báyìí ni wọ́n ṣe ń lo káàdì yìí.", "how_to_use_card": "Báyìí ni wọ́n ṣe ń lo káàdì yìí.",
"id": "Àmì Ìdánimọ̀: ", "id": "Àmì Ìdánimọ̀: ",
"if_you_dont_see_your_device": "Ti o ko ba ri ẹrọ rẹ loke, jọwọ rii daju pe a le jiji rẹ ati ṣiṣi!",
"ignor": "Ṣàìfiyèsí", "ignor": "Ṣàìfiyèsí",
"import": "gbe wọle", "import": "gbe wọle",
"importNFTs": "Gbe awọn NFT wọle", "importNFTs": "Gbe awọn NFT wọle",
@ -539,6 +540,7 @@
"recipient_address": "Àdírẹ́sì olùgbà", "recipient_address": "Àdírẹ́sì olùgbà",
"reconnect": "Ṣe àtúnse", "reconnect": "Ṣe àtúnse",
"reconnect_alert_text": "Ṣó dá ẹ lójú pé ẹ fẹ́ ṣe àtúnse?", "reconnect_alert_text": "Ṣó dá ẹ lójú pé ẹ fẹ́ ṣe àtúnse?",
"reconnect_your_hardware_wallet": "Ṣe atunṣe apamọwọ ohun elo rẹ",
"reconnection": "Àtúnṣe", "reconnection": "Àtúnṣe",
"red_dark_theme": "Akọle dudu pupa", "red_dark_theme": "Akọle dudu pupa",
"red_light_theme": "Akori ina pupa", "red_light_theme": "Akori ina pupa",

View file

@ -355,6 +355,7 @@
"how_to_use": "如何使用", "how_to_use": "如何使用",
"how_to_use_card": "如何使用这张卡", "how_to_use_card": "如何使用这张卡",
"id": "ID: ", "id": "ID: ",
"if_you_dont_see_your_device": "如果您在上面看不到设备,请确保您的分类帐已经清醒并解锁!",
"ignor": "忽视", "ignor": "忽视",
"import": "进口", "import": "进口",
"importNFTs": "导入 NFT", "importNFTs": "导入 NFT",
@ -538,6 +539,7 @@
"recipient_address": "收件人地址", "recipient_address": "收件人地址",
"reconnect": "重新连接", "reconnect": "重新连接",
"reconnect_alert_text": "您确定要重新连接吗?", "reconnect_alert_text": "您确定要重新连接吗?",
"reconnect_your_hardware_wallet": "重新连接您的硬件钱包",
"reconnection": "重新连接", "reconnection": "重新连接",
"red_dark_theme": "红色的黑暗主题", "red_dark_theme": "红色的黑暗主题",
"red_light_theme": "红灯主题", "red_light_theme": "红灯主题",