mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-11-17 01:37:40 +00:00
Merge branch 'refs/heads/main' into CW-679-Add-Ledger-Litecoin-Support
This commit is contained in:
commit
0473d28e9c
22 changed files with 275 additions and 48 deletions
2
.github/workflows/pr_test_build.yml
vendored
2
.github/workflows/pr_test_build.yml
vendored
|
@ -41,7 +41,7 @@ jobs:
|
|||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: "11.x"
|
||||
java-version: "17.x"
|
||||
- name: Configure placeholder git details
|
||||
run: |
|
||||
git config --global user.email "CI@cakewallet.com"
|
||||
|
|
|
@ -1,4 +1,19 @@
|
|||
-
|
||||
uri: ltc-electrum.cakewallet.com:50002
|
||||
useSSL: true
|
||||
isDefault: true
|
||||
isDefault: true
|
||||
-
|
||||
uri: litecoin.stackwallet.com:20063
|
||||
useSSL: true
|
||||
-
|
||||
uri: electrum-ltc.bysh.me:50002
|
||||
useSSL: true
|
||||
-
|
||||
uri: lightweight.fiatfaucet.com:50002
|
||||
useSSL: true
|
||||
-
|
||||
uri: electrum.ltc.xurious.com:50002
|
||||
useSSL: true
|
||||
-
|
||||
uri: backup.electrum-ltc.org:443
|
||||
useSSL: true
|
||||
|
|
|
@ -236,25 +236,37 @@ class ElectrumClient {
|
|||
return [];
|
||||
});
|
||||
|
||||
Future<Map<String, dynamic>> getTransactionRaw({required String hash}) async =>
|
||||
callWithTimeout(method: 'blockchain.transaction.get', params: [hash, true], timeout: 10000)
|
||||
.then((dynamic result) {
|
||||
if (result is Map<String, dynamic>) {
|
||||
return result;
|
||||
}
|
||||
Future<Map<String, dynamic>> getTransactionRaw({required String hash}) async {
|
||||
try {
|
||||
final result = await callWithTimeout(
|
||||
method: 'blockchain.transaction.get', params: [hash, true], timeout: 10000);
|
||||
if (result is Map<String, dynamic>) {
|
||||
return result;
|
||||
}
|
||||
} on RequestFailedTimeoutException catch (_) {
|
||||
return <String, dynamic>{};
|
||||
} catch (e) {
|
||||
print("getTransactionRaw: ${e.toString()}");
|
||||
return <String, dynamic>{};
|
||||
}
|
||||
return <String, dynamic>{};
|
||||
}
|
||||
|
||||
return <String, dynamic>{};
|
||||
});
|
||||
|
||||
Future<String> getTransactionHex({required String hash}) async =>
|
||||
callWithTimeout(method: 'blockchain.transaction.get', params: [hash, false], timeout: 10000)
|
||||
.then((dynamic result) {
|
||||
if (result is String) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return '';
|
||||
});
|
||||
Future<String> getTransactionHex({required String hash}) async {
|
||||
try {
|
||||
final result = await callWithTimeout(
|
||||
method: 'blockchain.transaction.get', params: [hash, false], timeout: 10000);
|
||||
if (result is String) {
|
||||
return result;
|
||||
}
|
||||
} on RequestFailedTimeoutException catch (_) {
|
||||
return '';
|
||||
} catch (e) {
|
||||
print("getTransactionHex: ${e.toString()}");
|
||||
return '';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
Future<String> broadcastTransaction(
|
||||
{required String transactionRaw,
|
||||
|
@ -353,14 +365,21 @@ class ElectrumClient {
|
|||
// "height": 520481,
|
||||
// "hex": "00000020890208a0ae3a3892aa047c5468725846577cfcd9b512b50000000000000000005dc2b02f2d297a9064ee103036c14d678f9afc7e3d9409cf53fd58b82e938e8ecbeca05a2d2103188ce804c4"
|
||||
// }
|
||||
Future<int?> getCurrentBlockChainTip() =>
|
||||
callWithTimeout(method: 'blockchain.headers.subscribe').then((result) {
|
||||
if (result is Map<String, dynamic>) {
|
||||
return result["height"] as int;
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
Future<int?> getCurrentBlockChainTip() async {
|
||||
try {
|
||||
final result = await callWithTimeout(method: 'blockchain.headers.subscribe');
|
||||
if (result is Map<String, dynamic>) {
|
||||
return result["height"] as int;
|
||||
}
|
||||
return null;
|
||||
} on RequestFailedTimeoutException catch (_) {
|
||||
return null;
|
||||
} catch (e) {
|
||||
print("getCurrentBlockChainTip: ${e.toString()}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
BehaviorSubject<Object>? chainTipSubscribe() {
|
||||
_id += 1;
|
||||
|
|
|
@ -59,6 +59,10 @@ dev_dependencies:
|
|||
hive_generator: ^1.1.3
|
||||
|
||||
dependency_overrides:
|
||||
ledger_flutter:
|
||||
git:
|
||||
url: https://github.com/cake-tech/ledger-flutter.git
|
||||
ref: cake-v3
|
||||
watcher: ^1.1.0
|
||||
|
||||
# For information on the generic Dart part of this file, see the
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:cw_core/pathForWallet.dart';
|
||||
import 'package:cw_core/utils/file.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/wallet_credentials.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
|
@ -42,4 +44,21 @@ abstract class WalletService<N extends WalletCredentials, RFS extends WalletCred
|
|||
await File(walletDirPath).copy(backupWalletDirPath);
|
||||
}
|
||||
}
|
||||
|
||||
Future<String> getSeeds(String name, String password, WalletType type) async {
|
||||
try {
|
||||
final path = await pathForWallet(name: name, type: type);
|
||||
final jsonSource = await read(path: path, password: password);
|
||||
try {
|
||||
final data = json.decode(jsonSource) as Map;
|
||||
return data['mnemonic'] as String? ?? '';
|
||||
} catch (_) {
|
||||
// if not a valid json
|
||||
return jsonSource.substring(0, 200);
|
||||
}
|
||||
} catch (_) {
|
||||
// if the file couldn't be opened or read
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ dependency_overrides:
|
|||
ledger_flutter:
|
||||
git:
|
||||
url: https://github.com/cake-tech/ledger-flutter.git
|
||||
ref: cake
|
||||
ref: cake-v3
|
||||
watcher: ^1.1.0
|
||||
|
||||
dev_dependencies:
|
||||
|
|
|
@ -42,12 +42,16 @@ class Subaddress {
|
|||
|
||||
List<Subaddress> getAllSubaddresses() {
|
||||
final size = monero.Wallet_numSubaddresses(wptr!, accountIndex: subaddress!.accountIndex);
|
||||
return List.generate(size, (index) {
|
||||
final list = List.generate(size, (index) {
|
||||
return Subaddress(
|
||||
accountIndex: subaddress!.accountIndex,
|
||||
addressIndex: index,
|
||||
);
|
||||
}).reversed.toList();
|
||||
if (list.length == 0) {
|
||||
list.add(Subaddress(addressIndex: subaddress!.accountIndex, accountIndex: 0));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
void addSubaddressSync({required int accountIndex, required String label}) {
|
||||
|
|
|
@ -110,7 +110,10 @@ Future<PendingTransactionDescription> createTransactionSync(
|
|||
})();
|
||||
|
||||
if (error != null) {
|
||||
final message = error;
|
||||
String message = error;
|
||||
if (message.contains("RPC error")) {
|
||||
message = "Invalid node response, please try again or switch node\n\ntrace: $message";
|
||||
}
|
||||
throw CreationTransactionException(message: message);
|
||||
}
|
||||
|
||||
|
|
|
@ -131,7 +131,7 @@ void storeSync() async {
|
|||
return monero.Wallet_synchronized(Pointer.fromAddress(addr));
|
||||
});
|
||||
if (lastStorePointer == wptr!.address &&
|
||||
lastStoreHeight + 5000 < monero.Wallet_blockChainHeight(wptr!) &&
|
||||
lastStoreHeight + 5000 > monero.Wallet_blockChainHeight(wptr!) &&
|
||||
!synchronized) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ import 'package:cw_core/transaction_priority.dart';
|
|||
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_monero/api/account_list.dart';
|
||||
import 'package:cw_monero/api/coins_info.dart';
|
||||
import 'package:cw_monero/api/monero_output.dart';
|
||||
import 'package:cw_monero/api/structs/pending_transaction.dart';
|
||||
|
|
|
@ -109,7 +109,7 @@ abstract class MoneroWalletAddressesBase extends WalletAddresses with Store {
|
|||
accountIndex: accountIndex,
|
||||
defaultLabel: defaultLabel,
|
||||
usedAddresses: usedAddresses.toList());
|
||||
subaddress = subaddressList.subaddresses.last;
|
||||
subaddress = (subaddressList.subaddresses.isEmpty) ? Subaddress(id: 0, address: address, label: defaultLabel) : subaddressList.subaddresses.last;
|
||||
address = subaddress!.address;
|
||||
}
|
||||
|
||||
|
|
|
@ -57,8 +57,11 @@ class MoneroRestoreWalletFromKeysCredentials extends WalletCredentials {
|
|||
final String spendKey;
|
||||
}
|
||||
|
||||
class MoneroWalletService extends WalletService<MoneroNewWalletCredentials,
|
||||
MoneroRestoreWalletFromSeedCredentials, MoneroRestoreWalletFromKeysCredentials, MoneroNewWalletCredentials> {
|
||||
class MoneroWalletService extends WalletService<
|
||||
MoneroNewWalletCredentials,
|
||||
MoneroRestoreWalletFromSeedCredentials,
|
||||
MoneroRestoreWalletFromKeysCredentials,
|
||||
MoneroNewWalletCredentials> {
|
||||
MoneroWalletService(this.walletInfoSource, this.unspentCoinsInfoSource);
|
||||
|
||||
final Box<WalletInfo> walletInfoSource;
|
||||
|
@ -183,11 +186,8 @@ class MoneroWalletService extends WalletService<MoneroNewWalletCredentials,
|
|||
final wmaddr = wmPtr.address;
|
||||
final waddr = openedWalletsByPath["$path/$wallet"]!.address;
|
||||
// await Isolate.run(() {
|
||||
monero.WalletManager_closeWallet(
|
||||
Pointer.fromAddress(wmaddr),
|
||||
Pointer.fromAddress(waddr),
|
||||
false
|
||||
);
|
||||
monero.WalletManager_closeWallet(
|
||||
Pointer.fromAddress(wmaddr), Pointer.fromAddress(waddr), false);
|
||||
// });
|
||||
openedWalletsByPath.remove("$path/$wallet");
|
||||
print("wallet closed");
|
||||
|
@ -248,7 +248,8 @@ class MoneroWalletService extends WalletService<MoneroNewWalletCredentials,
|
|||
|
||||
@override
|
||||
Future<MoneroWallet> restoreFromHardwareWallet(MoneroNewWalletCredentials credentials) {
|
||||
throw UnimplementedError("Restoring a Monero wallet from a hardware wallet is not yet supported!");
|
||||
throw UnimplementedError(
|
||||
"Restoring a Monero wallet from a hardware wallet is not yet supported!");
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -350,4 +351,24 @@ class MoneroWalletService extends WalletService<MoneroNewWalletCredentials,
|
|||
print(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String> getSeeds(String name, String password, WalletType type) async {
|
||||
try {
|
||||
final path = await pathForWallet(name: name, type: getType());
|
||||
|
||||
if (walletFilesExist(path)) {
|
||||
await repairOldAndroidWallet(name);
|
||||
}
|
||||
|
||||
await monero_wallet_manager.openWalletAsync({'path': path, 'password': password});
|
||||
final walletInfo = walletInfoSource.values
|
||||
.firstWhere((info) => info.id == WalletBase.idFor(name, getType()));
|
||||
final wallet = MoneroWallet(walletInfo: walletInfo, unspentCoinsInfo: unspentCoinsInfoSource);
|
||||
return wallet.seed;
|
||||
} catch (_) {
|
||||
// if the file couldn't be opened or read
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,12 +41,16 @@ class Subaddress {
|
|||
|
||||
List<Subaddress> getAllSubaddresses() {
|
||||
final size = wownero.Wallet_numSubaddresses(wptr!, accountIndex: subaddress!.accountIndex);
|
||||
return List.generate(size, (index) {
|
||||
final list = List.generate(size, (index) {
|
||||
return Subaddress(
|
||||
accountIndex: subaddress!.accountIndex,
|
||||
addressIndex: index,
|
||||
);
|
||||
}).reversed.toList();
|
||||
if (list.isEmpty) {
|
||||
list.add(Subaddress(addressIndex: 0, accountIndex: subaddress!.accountIndex));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
void addSubaddressSync({required int accountIndex, required String label}) {
|
||||
|
|
|
@ -109,7 +109,7 @@ abstract class WowneroWalletAddressesBase extends WalletAddresses with Store {
|
|||
accountIndex: accountIndex,
|
||||
defaultLabel: defaultLabel,
|
||||
usedAddresses: usedAddresses.toList());
|
||||
subaddress = subaddressList.subaddresses.last;
|
||||
subaddress = (subaddressList.subaddresses.isEmpty) ? Subaddress(id: 0, address: address, label: defaultLabel) : subaddressList.subaddresses.last;
|
||||
address = subaddress!.address;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:cake_wallet/core/generate_wallet_password.dart';
|
||||
import 'package:cake_wallet/core/key_service.dart';
|
||||
import 'package:cake_wallet/entities/preferences_key.dart';
|
||||
import 'package:cake_wallet/reactions/on_authentication_state_change.dart';
|
||||
import 'package:cake_wallet/utils/exception_handler.dart';
|
||||
import 'package:cw_core/cake_hive.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
|
@ -52,6 +55,12 @@ class WalletLoadingService {
|
|||
} catch (error, stack) {
|
||||
ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stack));
|
||||
|
||||
// try fetching the seeds of the corrupted wallet to show it to the user
|
||||
String corruptedWalletsSeeds = "Corrupted wallets seeds (if retrievable, empty otherwise):";
|
||||
try {
|
||||
corruptedWalletsSeeds += await _getCorruptedWalletSeeds(name, type);
|
||||
} catch (_) {}
|
||||
|
||||
// try opening another wallet that is not corrupted to give user access to the app
|
||||
final walletInfoSource = await CakeHive.openBox<WalletInfo>(WalletInfo.boxName);
|
||||
|
||||
|
@ -69,12 +78,23 @@ class WalletLoadingService {
|
|||
await sharedPreferences.setInt(
|
||||
PreferencesKey.currentWalletType, serializeToInt(wallet.type));
|
||||
|
||||
// if found a wallet that is not corrupted, then still display the seeds of the corrupted ones
|
||||
authenticatedErrorStreamController.add(corruptedWalletsSeeds);
|
||||
|
||||
return wallet;
|
||||
} catch (_) {}
|
||||
} catch (_) {
|
||||
// save seeds and show corrupted wallets' seeds to the user
|
||||
try {
|
||||
final seeds = await _getCorruptedWalletSeeds(walletInfo.name, walletInfo.type);
|
||||
if (!corruptedWalletsSeeds.contains(seeds)) {
|
||||
corruptedWalletsSeeds += seeds;
|
||||
}
|
||||
} catch (_) {}
|
||||
}
|
||||
}
|
||||
|
||||
// if all user's wallets are corrupted throw exception
|
||||
throw error;
|
||||
throw error.toString() + "\n\n" + corruptedWalletsSeeds;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,4 +116,11 @@ class WalletLoadingService {
|
|||
isPasswordUpdated = true;
|
||||
await sharedPreferences.setBool(key, isPasswordUpdated);
|
||||
}
|
||||
|
||||
Future<String> _getCorruptedWalletSeeds(String name, WalletType type) async {
|
||||
final walletService = walletServiceFactory.call(type);
|
||||
final password = await keyService.getWalletPassword(walletName: name);
|
||||
|
||||
return "\n\n$type ($name): ${await walletService.getSeeds(name, password, type)}";
|
||||
}
|
||||
}
|
||||
|
|
14
lib/di.dart
14
lib/di.dart
|
@ -1,3 +1,5 @@
|
|||
import 'dart:async' show Timer;
|
||||
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
import 'package:cake_wallet/anonpay/anonpay_api.dart';
|
||||
import 'package:cake_wallet/anonpay/anonpay_info_base.dart';
|
||||
|
@ -487,6 +489,7 @@ Future<void> setup({
|
|||
|
||||
if (loginError != null) {
|
||||
authPageState.changeProcessText('ERROR: ${loginError.toString()}');
|
||||
loginError = null;
|
||||
}
|
||||
|
||||
ReactionDisposer? _reaction;
|
||||
|
@ -498,6 +501,17 @@ Future<void> setup({
|
|||
linkViewModel.handleLink();
|
||||
}
|
||||
});
|
||||
|
||||
Timer.periodic(Duration(seconds: 1), (timer) {
|
||||
if (timer.tick > 30) {
|
||||
timer.cancel();
|
||||
}
|
||||
|
||||
if (loginError != null) {
|
||||
authPageState.changeProcessText('ERROR: ${loginError.toString()}');
|
||||
timer.cancel();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/utils/exception_handler.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
@ -8,9 +10,16 @@ import 'package:cake_wallet/store/authentication_store.dart';
|
|||
ReactionDisposer? _onAuthenticationStateChange;
|
||||
|
||||
dynamic loginError;
|
||||
StreamController<dynamic> authenticatedErrorStreamController = StreamController<dynamic>();
|
||||
|
||||
void startAuthenticationStateChange(
|
||||
AuthenticationStore authenticationStore, GlobalKey<NavigatorState> navigatorKey) {
|
||||
authenticatedErrorStreamController.stream.listen((event) {
|
||||
if (authenticationStore.state == AuthenticationState.allowed) {
|
||||
ExceptionHandler.showError(event.toString(), delayInSeconds: 3);
|
||||
}
|
||||
});
|
||||
|
||||
_onAuthenticationStateChange ??= autorun((_) async {
|
||||
final state = authenticationStore.state;
|
||||
|
||||
|
@ -26,6 +35,11 @@ void startAuthenticationStateChange(
|
|||
|
||||
if (state == AuthenticationState.allowed) {
|
||||
await navigatorKey.currentState!.pushNamedAndRemoveUntil(Routes.dashboard, (route) => false);
|
||||
if (!(await authenticatedErrorStreamController.stream.isEmpty)) {
|
||||
ExceptionHandler.showError(
|
||||
(await authenticatedErrorStreamController.stream.first).toString());
|
||||
authenticatedErrorStreamController.stream.drain();
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -250,6 +250,20 @@ class CryptoBalanceWidget extends StatelessWidget {
|
|||
Observer(builder: (context) {
|
||||
return Column(
|
||||
children: [
|
||||
if (dashboardViewModel.isMoneroWalletBrokenReasons.isNotEmpty) ...[
|
||||
SizedBox(height: 10),
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
|
||||
child: DashBoardRoundedCardWidget(
|
||||
customBorder: 30,
|
||||
title: "Monero wallet is broken",
|
||||
subTitle: "Here are the things that are broken:\n - "
|
||||
+dashboardViewModel.isMoneroWalletBrokenReasons.join("\n - ")
|
||||
+"\n\nPlease restart your wallet and if it doesn't help contact our support.",
|
||||
onTap: () {},
|
||||
)
|
||||
)
|
||||
],
|
||||
if (dashboardViewModel.showSilentPaymentsCard) ...[
|
||||
SizedBox(height: 10),
|
||||
Padding(
|
||||
|
|
|
@ -51,7 +51,9 @@ class MoneroAccountEditOrCreatePage extends BasePage {
|
|||
|
||||
await moneroAccountCreationViewModel.save();
|
||||
|
||||
Navigator.of(context).pop(_textController.text);
|
||||
if (context.mounted) {
|
||||
Navigator.of(context).pop(_textController.text);
|
||||
}
|
||||
},
|
||||
text: moneroAccountCreationViewModel.isEdit
|
||||
? S.of(context).rename
|
||||
|
|
|
@ -4,11 +4,13 @@ import 'package:cake_wallet/entities/preferences_key.dart';
|
|||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/main.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||
import 'package:cake_wallet/utils/show_bar.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cw_core/root_dir.dart';
|
||||
import 'package:device_info_plus/device_info_plus.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_mailer/flutter_mailer.dart';
|
||||
import 'package:cake_wallet/utils/package_info.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
@ -254,4 +256,53 @@ class ExceptionHandler {
|
|||
'productName': data.productName,
|
||||
};
|
||||
}
|
||||
|
||||
static void showError(String error, {int? delayInSeconds}) async {
|
||||
if (_hasError) {
|
||||
return;
|
||||
}
|
||||
_hasError = true;
|
||||
|
||||
if (delayInSeconds != null) {
|
||||
Future.delayed(Duration(seconds: delayInSeconds), () => _showCopyPopup(error));
|
||||
return;
|
||||
}
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback(
|
||||
(_) async => _showCopyPopup(error),
|
||||
);
|
||||
}
|
||||
|
||||
static Future<void> _showCopyPopup(String content) async {
|
||||
if (navigatorKey.currentContext != null) {
|
||||
final shouldCopy = await showPopUp<bool?>(
|
||||
context: navigatorKey.currentContext!,
|
||||
builder: (context) {
|
||||
return AlertWithTwoActions(
|
||||
isDividerExist: true,
|
||||
alertTitle: S.of(context).error,
|
||||
alertContent: content,
|
||||
rightButtonText: S.of(context).copy,
|
||||
leftButtonText: S.of(context).close,
|
||||
actionRightButton: () {
|
||||
Navigator.of(context).pop(true);
|
||||
},
|
||||
actionLeftButton: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
if (shouldCopy == true) {
|
||||
await Clipboard.setData(ClipboardData(text: content));
|
||||
await showBar<void>(
|
||||
navigatorKey.currentContext!,
|
||||
S.of(navigatorKey.currentContext!).copied_to_clipboard,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
_hasError = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -335,6 +335,23 @@ abstract class DashboardViewModelBase with Store {
|
|||
wallet.type == WalletType.wownero ||
|
||||
wallet.type == WalletType.haven;
|
||||
|
||||
@computed
|
||||
List<String> get isMoneroWalletBrokenReasons {
|
||||
if (wallet.type != WalletType.monero) return [];
|
||||
final keys = monero!.getKeys(wallet);
|
||||
List<String> errors = [
|
||||
if (keys['privateSpendKey'] == List.generate(64, (index) => "0").join("")) "Private spend key is 0",
|
||||
if (keys['privateViewKey'] == List.generate(64, (index) => "0").join("")) "private view key is 0",
|
||||
if (keys['publicSpendKey'] == List.generate(64, (index) => "0").join("")) "public spend key is 0",
|
||||
if (keys['publicViewKey'] == List.generate(64, (index) => "0").join("")) "private view key is 0",
|
||||
if (wallet.seed == null) "wallet seed is null",
|
||||
if (wallet.seed == "") "wallet seed is empty",
|
||||
if (monero!.getSubaddressList(wallet).getAll(wallet)[0].address == "41d7FXjswpK1111111111111111111111111111111111111111111111111111111111111111111111111111112KhNi4")
|
||||
"primary address is invalid, you won't be able to receive / spend funds",
|
||||
];
|
||||
return errors;
|
||||
}
|
||||
|
||||
@computed
|
||||
bool get hasSilentPayments => wallet.type == WalletType.bitcoin && !wallet.isHardwareWallet;
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ dependencies:
|
|||
url: https://github.com/cake-tech/device_display_brightness.git
|
||||
ref: master
|
||||
workmanager: ^0.5.1
|
||||
wakelock_plus: ^1.1.3
|
||||
wakelock_plus: ^1.2.5
|
||||
flutter_mailer: ^2.0.2
|
||||
device_info_plus: ^9.1.0
|
||||
base32: 2.1.3
|
||||
|
@ -133,7 +133,7 @@ dependency_overrides:
|
|||
ledger_flutter:
|
||||
git:
|
||||
url: https://github.com/cake-tech/ledger-flutter.git
|
||||
ref: cake-stax
|
||||
ref: cake-v3
|
||||
web3dart:
|
||||
git:
|
||||
url: https://github.com/cake-tech/web3dart.git
|
||||
|
|
Loading…
Reference in a new issue