Skip to content

Commit

Permalink
Merge pull request #22 from mik3mast3rs/chain-id
Browse files Browse the repository at this point in the history
Feat: manually change chain id
  • Loading branch information
alienc0der authored Jan 28, 2023
2 parents 6005f61 + c46a9bd commit b986874
Show file tree
Hide file tree
Showing 10 changed files with 155 additions and 20 deletions.
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

0 comments on commit b986874

Please sign in to comment.