fix: Testnet fixes

- Fix restore page button not working
- Move button to Advanced Settings
- Add testnet public node by default when selecting to use testnet
This commit is contained in:
Rafael Saes 2023-12-06 09:49:41 -03:00
parent ca188b1670
commit ed129782fc
10 changed files with 117 additions and 73 deletions

View file

@ -74,6 +74,7 @@ abstract class ElectrumWalletBase
}
: {}),
this.unspentCoinsInfo = unspentCoinsInfo,
this.isTestnet = networkType == bitcoin.testnet,
super(walletInfo) {
this.electrumClient = electrumClient ?? ElectrumClient();
this.walletInfo = walletInfo;
@ -122,6 +123,9 @@ abstract class ElectrumWalletBase
bitcoin.NetworkType networkType;
@override
bool? isTestnet;
@override
BitcoinWalletKeys get keys =>
BitcoinWalletKeys(wif: hd.wif!, privateKey: hd.privKey!, publicKey: hd.pubKey!);

View file

@ -88,4 +88,6 @@ abstract class WalletBase<BalanceType extends Balance, HistoryType extends Trans
Future<void> renameWalletFiles(String newWalletName);
String signMessage(String message, {String? address = null}) => throw UnimplementedError();
bool? isTestnet;
}

View file

@ -23,6 +23,10 @@ import 'package:collection/collection.dart';
const newCakeWalletMoneroUri = 'xmr-node.cakewallet.com:18081';
const cakeWalletBitcoinElectrumUri = 'electrum.cakewallet.com:50002';
const publicBitcoinTestnetElectrumAddress = 'electrum.blockstream.info';
const publicBitcoinTestnetElectrumPort = '60002';
const publicBitcoinTestnetElectrumUri =
'$publicBitcoinTestnetElectrumAddress:$publicBitcoinTestnetElectrumPort';
const cakeWalletLitecoinElectrumUri = 'ltc-electrum.cakewallet.com:50002';
const havenDefaultNodeUri = 'nodes.havenprotocol.org:443';
const ethereumDefaultNodeUri = 'ethereum.publicnode.com';
@ -82,8 +86,7 @@ Future<void> defaultSettingsMigration(
sharedPreferences: sharedPreferences, nodes: nodes);
await changeLitecoinCurrentElectrumServerToDefault(
sharedPreferences: sharedPreferences, nodes: nodes);
await changeHavenCurrentNodeToDefault(
sharedPreferences: sharedPreferences, nodes: nodes);
await changeHavenCurrentNodeToDefault(sharedPreferences: sharedPreferences, nodes: nodes);
await changeBitcoinCashCurrentNodeToDefault(
sharedPreferences: sharedPreferences, nodes: nodes);
@ -313,6 +316,12 @@ Node? getBitcoinDefaultElectrumServer({required Box<Node> nodes}) {
nodes.values.firstWhereOrNull((node) => node.type == WalletType.bitcoin);
}
Node? getBitcoinTestnetDefaultElectrumServer({required Box<Node> nodes}) {
return nodes.values
.firstWhereOrNull((Node node) => node.uriRaw == publicBitcoinTestnetElectrumUri) ??
nodes.values.firstWhereOrNull((node) => node.type == WalletType.bitcoin);
}
Node? getLitecoinDefaultElectrumServer({required Box<Node> nodes}) {
return nodes.values
.firstWhereOrNull((Node node) => node.uriRaw == cakeWalletLitecoinElectrumUri) ??
@ -340,9 +349,9 @@ Node? getNanoDefaultPowNode({required Box<Node> nodes}) {
}
Node? getBitcoinCashDefaultElectrumServer({required Box<Node> nodes}) {
return nodes.values.firstWhereOrNull(
(Node node) => node.uriRaw == cakeWalletBitcoinCashDefaultNodeUri)
?? nodes.values.firstWhereOrNull((node) => node.type == WalletType.bitcoinCash);
return nodes.values
.firstWhereOrNull((Node node) => node.uriRaw == cakeWalletBitcoinCashDefaultNodeUri) ??
nodes.values.firstWhereOrNull((node) => node.type == WalletType.bitcoinCash);
}
Node getMoneroDefaultNode({required Box<Node> nodes}) {
@ -365,8 +374,15 @@ Node getMoneroDefaultNode({required Box<Node> nodes}) {
}
Future<void> changeBitcoinCurrentElectrumServerToDefault(
{required SharedPreferences sharedPreferences, required Box<Node> nodes}) async {
final server = getBitcoinDefaultElectrumServer(nodes: nodes);
{required SharedPreferences sharedPreferences,
required Box<Node> nodes,
bool? isTestnet}) async {
Node? server;
if (isTestnet == true) {
server = getBitcoinTestnetDefaultElectrumServer(nodes: nodes);
} else {
server = getBitcoinDefaultElectrumServer(nodes: nodes);
}
final serverId = server?.key as int? ?? 0;
await sharedPreferences.setInt(PreferencesKey.currentBitcoinElectrumSererIdKey, serverId);
@ -381,8 +397,7 @@ Future<void> changeLitecoinCurrentElectrumServerToDefault(
}
Future<void> changeBitcoinCashCurrentNodeToDefault(
{required SharedPreferences sharedPreferences,
required Box<Node> nodes}) async {
{required SharedPreferences sharedPreferences, required Box<Node> nodes}) async {
final server = getBitcoinCashDefaultElectrumServer(nodes: nodes);
final serverId = server?.key as int ?? 0;
@ -538,34 +553,30 @@ Future<void> checkCurrentNodes(
final currentMoneroNodeId = sharedPreferences.getInt(PreferencesKey.currentNodeIdKey);
final currentBitcoinElectrumSeverId =
sharedPreferences.getInt(PreferencesKey.currentBitcoinElectrumSererIdKey);
final currentLitecoinElectrumSeverId = sharedPreferences
.getInt(PreferencesKey.currentLitecoinElectrumSererIdKey);
final currentHavenNodeId = sharedPreferences
.getInt(PreferencesKey.currentHavenNodeIdKey);
final currentEthereumNodeId = sharedPreferences
.getInt(PreferencesKey.currentEthereumNodeIdKey);
final currentNanoNodeId = sharedPreferences
.getInt(PreferencesKey.currentNanoNodeIdKey);
final currentNanoPowNodeId = sharedPreferences
.getInt(PreferencesKey.currentNanoPowNodeIdKey);
final currentBitcoinCashNodeId = sharedPreferences
.getInt(PreferencesKey.currentBitcoinCashNodeIdKey);
final currentMoneroNode = nodeSource.values.firstWhereOrNull(
(node) => node.key == currentMoneroNodeId);
final currentBitcoinElectrumServer = nodeSource.values.firstWhereOrNull(
(node) => node.key == currentBitcoinElectrumSeverId);
final currentLitecoinElectrumServer = nodeSource.values.firstWhereOrNull(
(node) => node.key == currentLitecoinElectrumSeverId);
final currentHavenNodeServer = nodeSource.values.firstWhereOrNull(
(node) => node.key == currentHavenNodeId);
final currentEthereumNodeServer = nodeSource.values.firstWhereOrNull(
(node) => node.key == currentEthereumNodeId);
final currentLitecoinElectrumSeverId =
sharedPreferences.getInt(PreferencesKey.currentLitecoinElectrumSererIdKey);
final currentHavenNodeId = sharedPreferences.getInt(PreferencesKey.currentHavenNodeIdKey);
final currentEthereumNodeId = sharedPreferences.getInt(PreferencesKey.currentEthereumNodeIdKey);
final currentNanoNodeId = sharedPreferences.getInt(PreferencesKey.currentNanoNodeIdKey);
final currentNanoPowNodeId = sharedPreferences.getInt(PreferencesKey.currentNanoPowNodeIdKey);
final currentBitcoinCashNodeId =
sharedPreferences.getInt(PreferencesKey.currentBitcoinCashNodeIdKey);
final currentMoneroNode =
nodeSource.values.firstWhereOrNull((node) => node.key == currentMoneroNodeId);
final currentBitcoinElectrumServer =
nodeSource.values.firstWhereOrNull((node) => node.key == currentBitcoinElectrumSeverId);
final currentLitecoinElectrumServer =
nodeSource.values.firstWhereOrNull((node) => node.key == currentLitecoinElectrumSeverId);
final currentHavenNodeServer =
nodeSource.values.firstWhereOrNull((node) => node.key == currentHavenNodeId);
final currentEthereumNodeServer =
nodeSource.values.firstWhereOrNull((node) => node.key == currentEthereumNodeId);
final currentNanoNodeServer =
nodeSource.values.firstWhereOrNull((node) => node.key == currentNanoNodeId);
nodeSource.values.firstWhereOrNull((node) => node.key == currentNanoNodeId);
final currentNanoPowNodeServer =
powNodeSource.values.firstWhereOrNull((node) => node.key == currentNanoPowNodeId);
final currentBitcoinCashNodeServer = nodeSource.values.firstWhereOrNull(
(node) => node.key == currentBitcoinCashNodeId);
powNodeSource.values.firstWhereOrNull((node) => node.key == currentNanoPowNodeId);
final currentBitcoinCashNodeServer =
nodeSource.values.firstWhereOrNull((node) => node.key == currentBitcoinCashNodeId);
if (currentMoneroNode == null) {
final newCakeWalletNode = Node(uri: newCakeWalletMoneroUri, type: WalletType.monero);
await nodeSource.add(newCakeWalletNode);
@ -617,8 +628,7 @@ Future<void> checkCurrentNodes(
if (currentBitcoinCashNodeServer == null) {
final node = Node(uri: cakeWalletBitcoinCashDefaultNodeUri, type: WalletType.bitcoinCash);
await nodeSource.add(node);
await sharedPreferences.setInt(
PreferencesKey.currentBitcoinCashNodeIdKey, node.key as int);
await sharedPreferences.setInt(PreferencesKey.currentBitcoinCashNodeIdKey, node.key as int);
}
}

View file

@ -531,10 +531,15 @@ Route<dynamic> createRoute(RouteSettings settings) {
builder: (_) => getIt.get<WebViewPage>(param1: title, param2: url));
case Routes.advancedPrivacySettings:
final type = settings.arguments as WalletType;
final args = settings.arguments as List<dynamic>;
final type = args.first as WalletType;
final useTestnet = args[1] as bool?;
final toggleTestnet = args[2] as Function(bool? val);
return CupertinoPageRoute<void>(
builder: (_) => AdvancedPrivacySettingsPage(
useTestnet,
toggleTestnet,
getIt.get<AdvancedPrivacySettingsViewModel>(param1: type),
getIt.get<NodeCreateOrEditViewModel>(param1: type, param2: false),
));

View file

@ -1,3 +1,4 @@
import 'package:cake_wallet/entities/default_settings_migration.dart';
import 'package:cake_wallet/entities/exchange_api_mode.dart';
import 'package:cake_wallet/entities/fiat_api_mode.dart';
import 'package:cake_wallet/entities/seed_phrase_length.dart';
@ -10,6 +11,7 @@ import 'package:cake_wallet/themes/extensions/new_wallet_theme.dart';
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart';
import 'package:cake_wallet/view_model/settings/choices_list_item.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/generated/i18n.dart';
@ -18,7 +20,8 @@ import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
class AdvancedPrivacySettingsPage extends BasePage {
AdvancedPrivacySettingsPage(this.advancedPrivacySettingsViewModel, this.nodeViewModel);
AdvancedPrivacySettingsPage(this.useTestnet, this.toggleUseTestnet,
this.advancedPrivacySettingsViewModel, this.nodeViewModel);
final AdvancedPrivacySettingsViewModel advancedPrivacySettingsViewModel;
final NodeCreateOrEditViewModel nodeViewModel;
@ -26,18 +29,26 @@ class AdvancedPrivacySettingsPage extends BasePage {
@override
String get title => S.current.privacy_settings;
final bool? useTestnet;
final Function(bool? val) toggleUseTestnet;
@override
Widget body(BuildContext context) =>
AdvancedPrivacySettingsBody(advancedPrivacySettingsViewModel, nodeViewModel);
Widget body(BuildContext context) => AdvancedPrivacySettingsBody(
useTestnet, toggleUseTestnet, advancedPrivacySettingsViewModel, nodeViewModel);
}
class AdvancedPrivacySettingsBody extends StatefulWidget {
const AdvancedPrivacySettingsBody(this.privacySettingsViewModel, this.nodeViewModel, {Key? key})
const AdvancedPrivacySettingsBody(
this.useTestnet, this.toggleUseTestnet, this.privacySettingsViewModel, this.nodeViewModel,
{Key? key})
: super(key: key);
final AdvancedPrivacySettingsViewModel privacySettingsViewModel;
final NodeCreateOrEditViewModel nodeViewModel;
final bool? useTestnet;
final Function(bool? val) toggleUseTestnet;
@override
_AdvancedPrivacySettingsBodyState createState() => _AdvancedPrivacySettingsBodyState();
}
@ -46,9 +57,14 @@ class _AdvancedPrivacySettingsBodyState extends State<AdvancedPrivacySettingsBod
_AdvancedPrivacySettingsBodyState();
final _formKey = GlobalKey<FormState>();
bool? testnetValue;
@override
Widget build(BuildContext context) {
if (testnetValue == null && widget.useTestnet != null) {
testnetValue = widget.useTestnet;
}
return Container(
padding: EdgeInsets.only(top: 24),
child: ScrollableWithBottomSection(
@ -119,6 +135,19 @@ class _AdvancedPrivacySettingsBodyState extends State<AdvancedPrivacySettingsBod
),
);
}),
if (widget.privacySettingsViewModel.type == WalletType.bitcoin)
Builder(builder: (_) {
final val = testnetValue!;
return SettingsSwitcherCell(
title: S.current.use_testnet,
value: val,
onValueChange: (_, __) {
setState(() {
testnetValue = !val;
});
widget.toggleUseTestnet(testnetValue);
});
}),
],
),
bottomSectionPadding: EdgeInsets.all(24),
@ -131,6 +160,11 @@ class _AdvancedPrivacySettingsBodyState extends State<AdvancedPrivacySettingsBod
return;
}
widget.nodeViewModel.save();
} else if (testnetValue == true) {
widget.nodeViewModel.address = publicBitcoinTestnetElectrumAddress;
widget.nodeViewModel.port = publicBitcoinTestnetElectrumPort;
widget.nodeViewModel.save();
}

View file

@ -40,8 +40,8 @@ class NewWalletPage extends BasePage {
String get title => S.current.new_wallet;
@override
Widget body(BuildContext context) => WalletNameForm(
_walletNewVM, currentTheme.type == ThemeType.dark ? walletNameImage : walletNameLightImage, _settingsStore);
Widget body(BuildContext context) => WalletNameForm(_walletNewVM,
currentTheme.type == ThemeType.dark ? walletNameImage : walletNameLightImage, _settingsStore);
}
class WalletNameForm extends StatefulWidget {
@ -188,7 +188,6 @@ class _WalletNameFormState extends State<WalletNameForm> {
),
),
),
if (_walletNewVM.hasLanguageSelector) ...[
if (_walletNewVM.hasSeedType) ...[
Observer(
@ -224,12 +223,6 @@ class _WalletNameFormState extends State<WalletNameForm> {
),
)
],
Observer(builder: (context) {
return SettingsSwitcherCell(
title: S.current.use_testnet,
value: widget._walletNewVM.useTestnet,
onValueChange: (_, __) => widget._walletNewVM.toggleUseTestnet());
}),
],
),
),
@ -252,8 +245,11 @@ class _WalletNameFormState extends State<WalletNameForm> {
const SizedBox(height: 25),
GestureDetector(
onTap: () {
Navigator.of(context)
.pushNamed(Routes.advancedPrivacySettings, arguments: _walletNewVM.type);
Navigator.of(context).pushNamed(Routes.advancedPrivacySettings, arguments: [
_walletNewVM.type,
_walletNewVM.useTestnet,
_walletNewVM.toggleUseTestnet
]);
},
child: Text(S.of(context).advanced_settings),
),

View file

@ -1,6 +1,5 @@
import 'package:cake_wallet/core/wallet_name_validator.dart';
import 'package:cake_wallet/entities/generate_name.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
@ -9,7 +8,6 @@ import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
import 'package:cake_wallet/src/widgets/blockchain_height_widget.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:cake_wallet/entities/seed_type.dart';
import 'package:cake_wallet/src/widgets/picker.dart';
import 'package:cake_wallet/src/widgets/seed_language_picker.dart';
@ -25,8 +23,6 @@ class WalletRestoreFromSeedForm extends StatefulWidget {
this.onHeightOrDateEntered,
this.onSeedChange,
this.onLanguageChange,
required this.toggleTestnet,
required this.isTestnet,
}) : super(key: key);
final WalletType type;
@ -37,9 +33,6 @@ class WalletRestoreFromSeedForm extends StatefulWidget {
final void Function(String)? onSeedChange;
final void Function(String)? onLanguageChange;
bool isTestnet;
final Function() toggleTestnet;
@override
WalletRestoreFromSeedFormState createState() => WalletRestoreFromSeedFormState('English');
}
@ -185,12 +178,6 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
key: blockchainHeightKey,
onHeightOrDateEntered: widget.onHeightOrDateEntered,
hasDatePicker: widget.type == WalletType.monero),
Observer(builder: (_) {
return SettingsSwitcherCell(
title: S.current.use_testnet,
value: widget.isTestnet,
onValueChange: (_, __) => widget.toggleTestnet());
}),
]));
}

View file

@ -37,8 +37,6 @@ class WalletRestorePage extends BasePage {
switch (mode) {
case WalletRestoreMode.seed:
_pages.add(WalletRestoreFromSeedForm(
isTestnet: walletRestoreViewModel.useTestnet,
toggleTestnet: walletRestoreViewModel.toggleUseTestnet,
displayBlockHeightSelector:
walletRestoreViewModel.hasBlockchainHeightLanguageSelector,
displayLanguageSelector: walletRestoreViewModel.hasSeedLanguageSelector,
@ -209,8 +207,12 @@ class WalletRestorePage extends BasePage {
const SizedBox(height: 25),
GestureDetector(
onTap: () {
Navigator.of(context).pushNamed(Routes.advancedPrivacySettings,
arguments: walletRestoreViewModel.type);
Navigator.of(context)
.pushNamed(Routes.advancedPrivacySettings, arguments: [
walletRestoreViewModel.type,
walletRestoreViewModel.useTestnet,
walletRestoreViewModel.toggleUseTestnet
]);
},
child: Text(S.of(context).advanced_settings),
),

View file

@ -52,7 +52,11 @@ abstract class NodeListViewModelBase with Store {
switch (_appStore.wallet!.type) {
case WalletType.bitcoin:
node = getBitcoinDefaultElectrumServer(nodes: _nodeSource)!;
if (_appStore.wallet!.isTestnet == true) {
node = getBitcoinTestnetDefaultElectrumServer(nodes: _nodeSource)!;
} else {
node = getBitcoinDefaultElectrumServer(nodes: _nodeSource)!;
}
break;
case WalletType.monero:
node = getMoneroDefaultNode(nodes: _nodeSource);

View file

@ -102,7 +102,7 @@ abstract class WalletCreationVMBase with Store {
throw UnimplementedError();
@action
void toggleUseTestnet() {
_useTestnet = !_useTestnet;
void toggleUseTestnet(bool? value) {
_useTestnet = value ?? !_useTestnet;
}
}