Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: manually change chain id #22

Merged
merged 4 commits into from
Jan 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions lib/utils/constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,10 @@ const bool kLaunchAtStartupDefaultValue = false;
const String kEnableDesktopNotificationsKey = 'enable_desktop_notifications';
const bool kEnableDesktopNotificationsDefaultValue = false;

/// Node management
const String kChainIdKey = 'chain_id';
const int kChainIdDefaultValue = 1; // 1 corresponds to Alphanet

// Display constants
const String kThemeModeKey = 'theme_mode_key';
const ThemeMode kDefaultThemeMode = ThemeMode.dark;
Expand Down
11 changes: 11 additions & 0 deletions lib/utils/init_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import 'package:zenon_syrius_wallet_flutter/utils/global.dart';
import 'package:zenon_syrius_wallet_flutter/utils/keystore_utils.dart';
import 'package:zenon_syrius_wallet_flutter/utils/node_utils.dart';
import 'package:zenon_syrius_wallet_flutter/utils/widget_utils.dart';
import 'package:znn_sdk_dart/znn_sdk_dart.dart';

class InitUtils {
static Future<void> initApp(BuildContext context) async {
Expand All @@ -21,12 +22,22 @@ class InitUtils {
await KeyStoreUtils.setKeyStorePath();
await _setNumUnlockFailedAttempts();
await NodeUtils.setNode();
_setChainId();
await NodeUtils.loadDbNodes();
} catch (e) {
rethrow;
}
}

static void _setChainId() {
setChainIdentifier(
chainIdentifier: sharedPrefsService!.get(
kChainIdKey,
defaultValue: kChainIdDefaultValue,
),
);
}

static Future<void> _setNumUnlockFailedAttempts() async {
if (sharedPrefsService == null) {
sharedPrefsService = await sl.getAsync<SharedPrefsService>();
Expand Down
14 changes: 13 additions & 1 deletion lib/utils/input_validators.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,19 @@ class InputValidators {
return (value ?? '').isEmpty ? '$fieldName must not be empty' : null;
}

static String? validateNumber(String? value) {
static String? validateNumber(String? number) {
try {
if (number == null) {
return 'Add a number';
}
int.parse(number);
return null;
} catch (e) {
return 'Input is not a valid number';
}
}

static String? validateAmount(String? value) {
if (value != null) {
try {
if (value.isEmpty) {
Expand Down
12 changes: 0 additions & 12 deletions lib/utils/node_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import 'package:zenon_syrius_wallet_flutter/main.dart';
import 'package:zenon_syrius_wallet_flutter/model/model.dart';
import 'package:zenon_syrius_wallet_flutter/utils/constants.dart';
import 'package:zenon_syrius_wallet_flutter/utils/global.dart';
import 'package:zenon_syrius_wallet_flutter/utils/logger.dart';
import 'package:zenon_syrius_wallet_flutter/utils/notification_utils.dart';
import 'package:znn_sdk_dart/znn_sdk_dart.dart';

Expand All @@ -22,17 +21,6 @@ class NodeUtils {
url,
retry: false,
);

if (connectionStatus) {
try {
await zenon!.ledger.getFrontierMomentum().then((value) {
setChainIdentifier(chainIdentifier: value.chainIdentifier.toInt());
});
} catch (e) {
Logger.logError(e);
}
}

return connectionStatus;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -705,7 +705,7 @@ class _MainPillarsState extends State<PillarsStepperContainer> {
child: InputField(
enabled: false,
controller: _znnAmountController,
validator: InputValidators.validateNumber,
validator: InputValidators.validateAmount,
),
),
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,7 @@ class _MainSentinelsState extends State<SentinelsStepperContainer> {
child: InputField(
enabled: false,
controller: _znnAmountController,
validator: InputValidators.validateNumber,
validator: InputValidators.validateAmount,
),
),
],
Expand Down
120 changes: 119 additions & 1 deletion lib/widgets/modular_widgets/settings_widgets/node_management.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'dart:io';
import 'dart:isolate';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:hive/hive.dart';
import 'package:wakelock/wakelock.dart';
import 'package:zenon_syrius_wallet_flutter/blocs/blocs.dart';
Expand All @@ -14,6 +15,7 @@ import 'package:zenon_syrius_wallet_flutter/utils/input_validators.dart';
import 'package:zenon_syrius_wallet_flutter/utils/node_utils.dart';
import 'package:zenon_syrius_wallet_flutter/utils/notification_utils.dart';
import 'package:zenon_syrius_wallet_flutter/widgets/widgets.dart';
import 'package:znn_sdk_dart/znn_sdk_dart.dart';

class NodeManagement extends StatefulWidget {
final VoidCallback onNodeChangedCallback;
Expand All @@ -32,17 +34,32 @@ class _NodeManagementState extends State<NodeManagement> {

final GlobalKey<LoadingButtonState> _confirmNodeButtonKey = GlobalKey();
final GlobalKey<LoadingButtonState> _addNodeButtonKey = GlobalKey();
final GlobalKey<LoadingButtonState> _confirmChainIdButtonKey = GlobalKey();

TextEditingController _newNodeController = TextEditingController();
GlobalKey<FormState> _newNodeKey = GlobalKey();

TextEditingController _newChainIdController = TextEditingController();
GlobalKey<FormState> _newChainIdKey = GlobalKey();

late String _selectedNodeConfirmed;
late int _currentChainId;

int get _newChainId => int.parse(_newChainIdController.text);

@override
void didChangeDependencies() {
super.didChangeDependencies();
_selectedNode ??= kCurrentNode!;
_selectedNodeConfirmed = _selectedNode!;
_initCurrentChainId();
}

void _initCurrentChainId() {
_currentChainId = sharedPrefsService!.get(
kChainIdKey,
defaultValue: kChainIdDefaultValue,
);
}

@override
Expand All @@ -61,14 +78,18 @@ class _NodeManagementState extends State<NodeManagement> {
return ListView(
shrinkWrap: true,
children: [
CustomExpandablePanel(
'Chain id selection',
_getChainIdSelectionExpandableChild(),
),
CustomExpandablePanel(
'Node selection',
_getNodeSelectionExpandableChild(),
),
CustomExpandablePanel(
'Add node',
_getAddNodeExpandableChild(),
)
),
],
);
}
Expand Down Expand Up @@ -134,6 +155,7 @@ class _NodeManagementState extends State<NodeManagement> {
_selectedNode,
);
kCurrentNode = _selectedNode!;
await _checkForChainIdDifferences();
_sendChangingNodeSuccessNotification();
widget.onNodeChangedCallback();
} else {
Expand Down Expand Up @@ -266,6 +288,7 @@ class _NodeManagementState extends State<NodeManagement> {
@override
void dispose() {
_newNodeController.dispose();
_newChainIdController.dispose();
super.dispose();
}

Expand All @@ -279,4 +302,99 @@ class _NodeManagementState extends State<NodeManagement> {
),
);
}

Widget _getChainIdSelectionExpandableChild() {
return Column(
children: [
Text(
'Current chain id: $_currentChainId',
style: Theme.of(context).textTheme.subtitle1,
),
kVerticalSpacing,
Form(
key: _newChainIdKey,
autovalidateMode: AutovalidateMode.onUserInteraction,
child: InputField(
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
],
controller: _newChainIdController,
hintText: 'Node address with port',
onSubmitted: (value) {
if (_ifUserInputValid()) {
_onAddNodePressed();
}
},
onChanged: (String value) {
if (value.isNotEmpty) {
setState(() {});
}
},
validator: InputValidators.validateNumber,
),
),
kVerticalSpacing,
LoadingButton.settings(
onPressed: _isChainIdSelectionInputIsValid()
? _onConfirmChainIdPressed
: null,
text: 'Confirm chain id',
key: _confirmChainIdButtonKey,
),
],
);
}

bool _isChainIdSelectionInputIsValid() =>
InputValidators.validateNumber(_newChainIdController.text) == null &&
_newChainId != _currentChainId;

Future<void> _onConfirmChainIdPressed() async {
try {
_confirmChainIdButtonKey.currentState?.animateForward();
setChainIdentifier(chainIdentifier: _newChainId);
await sharedPrefsService!.put(kChainIdKey, _newChainId);
_sendSuccessfullyChangedChainIdNotification(_newChainId);
_initCurrentChainId();
_newChainIdController = TextEditingController();
_newChainIdKey = GlobalKey();
} catch (e) {
NotificationUtils.sendNotificationError(
e,
'Error while saving new chain id',
);
} finally {
_confirmChainIdButtonKey.currentState?.animateReverse();
}
}

void _sendSuccessfullyChangedChainIdNotification(int newChainId) {
sl.get<NotificationsBloc>().addNotification(
WalletNotification(
title: 'Successfully changed chain id to: $newChainId',
timestamp: DateTime.now().millisecondsSinceEpoch,
details:
'Successfully changed chain id from $_currentChainId to $_newChainId',
type: NotificationType.changedNode,
),
);
}

Future<void> _checkForChainIdDifferences() async {
await zenon!.ledger.getFrontierMomentum().then((momentum) {
int nodeChainId = momentum.chainIdentifier;
if (nodeChainId != _currentChainId) {
_showDifferentChainIdDialog(nodeChainId, _currentChainId);
}
});
}

void _showDifferentChainIdDialog(int nodeChainId, int currentChainId) {
showOkDialog(
context: context,
title: 'Different chain id',
description: 'The new node: $_selectedNode has a different '
'chain id ($nodeChainId) than the current one ($currentChainId)',
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ class _ReceiveLargeCardState extends State<ReceiveLargeCard> {
autovalidateMode:
AutovalidateMode.onUserInteraction,
child: InputField(
validator: InputValidators.validateNumber,
validator: InputValidators.validateAmount,
onChanged: (value) => setState(() {}),
inputFormatters:
FormatUtils.getAmountTextInputFormatters(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ class _ReceiveMediumCardState extends State<ReceiveMediumCard> {
key: _amountKey,
autovalidateMode: AutovalidateMode.onUserInteraction,
child: InputField(
validator: InputValidators.validateNumber,
validator: InputValidators.validateAmount,
onChanged: (value) => setState(() {}),
inputFormatters:
FormatUtils.getAmountTextInputFormatters(
Expand Down
6 changes: 4 additions & 2 deletions lib/widgets/reusable_widgets/dialogs.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ showOkDialog({
required BuildContext context,
required String title,
required String description,
required VoidCallback onActionButtonPressed,
VoidCallback? onActionButtonPressed,
}) =>
showDialog(
context: context,
Expand All @@ -14,7 +14,9 @@ showOkDialog({
content: Text(description),
actions: [
TextButton(
onPressed: onActionButtonPressed,
onPressed: onActionButtonPressed ?? () {
Navigator.pop(context);
},
child: Text(
'OK',
style: Theme.of(context).textTheme.bodyText1,
Expand Down