Skip to content

Commit a088e2c

Browse files
committed
various masternode related fixes and improvements
1 parent c52cdfb commit a088e2c

4 files changed

Lines changed: 129 additions & 73 deletions

File tree

lib/pages/masternodes/create_masternode_view.dart

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,16 @@ import '../../widgets/desktop/desktop_dialog_close_button.dart';
1111
import 'sub_widgets/register_masternode_form.dart';
1212

1313
class CreateMasternodeView extends ConsumerStatefulWidget {
14-
const CreateMasternodeView({super.key, required this.firoWalletId});
14+
const CreateMasternodeView({
15+
super.key,
16+
required this.firoWalletId,
17+
this.popTxidOnSuccess = true,
18+
});
1519

1620
static const routeName = "/createMasternodeView";
1721

1822
final String firoWalletId;
23+
final bool popTxidOnSuccess;
1924

2025
@override
2126
ConsumerState<CreateMasternodeView> createState() =>
@@ -100,7 +105,14 @@ class _CreateMasternodeDialogState extends ConsumerState<CreateMasternodeView> {
100105
),
101106
),
102107
),
103-
child: RegisterMasternodeForm(firoWalletId: widget.firoWalletId),
108+
child: RegisterMasternodeForm(
109+
firoWalletId: widget.firoWalletId,
110+
onRegistrationSuccess: (txid) {
111+
if (widget.popTxidOnSuccess && mounted) {
112+
Navigator.of(context, rootNavigator: Util.isDesktop).pop(txid);
113+
}
114+
},
115+
),
104116
),
105117
);
106118
}

lib/pages/masternodes/masternodes_home_view.dart

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import 'package:flutter_svg/svg.dart';
55
import '../../providers/global/wallets_provider.dart';
66
import '../../themes/stack_colors.dart';
77
import '../../utilities/assets.dart';
8+
import '../../utilities/logger.dart';
89
import '../../utilities/text_styles.dart';
910
import '../../utilities/util.dart';
1011
import '../../wallets/wallet/impl/firo_wallet.dart';
@@ -14,6 +15,7 @@ import '../../widgets/desktop/desktop_scaffold.dart';
1415
import '../../widgets/desktop/primary_button.dart';
1516
import '../../widgets/dialogs/s_dialog.dart';
1617
import '../../widgets/loading_indicator.dart';
18+
import '../../widgets/stack_dialog.dart';
1719
import 'create_masternode_view.dart';
1820
import 'sub_widgets/masternodes_list.dart';
1921
import 'sub_widgets/masternodes_table_desktop.dart';
@@ -33,13 +35,40 @@ class MasternodesHomeView extends ConsumerStatefulWidget {
3335
class _MasternodesHomeViewState extends ConsumerState<MasternodesHomeView> {
3436
late Future<List<MasternodeInfo>> _masternodesFuture;
3537

36-
void _showDesktopCreateMasternodeDialog() {
37-
showDialog<void>(
38+
Future<void> _showDesktopCreateMasternodeDialog() async {
39+
final txid = await showDialog<Object>(
3840
context: context,
3941
barrierDismissible: true,
4042
builder: (context) =>
4143
SDialog(child: CreateMasternodeView(firoWalletId: widget.walletId)),
4244
);
45+
_handleSuccessTxid(txid);
46+
}
47+
48+
void _handleSuccessTxid(Object? txid) {
49+
Logging.instance.i(
50+
"$runtimeType _handleSuccessTxid($txid) called where mounted=$mounted",
51+
);
52+
if (mounted && txid is String) {
53+
setState(() {
54+
_masternodesFuture =
55+
(ref.read(pWallets).getWallet(widget.walletId) as FiroWallet)
56+
.getMyMasternodes();
57+
});
58+
59+
showDialog<void>(
60+
context: context,
61+
builder: (_) => StackOkDialog(
62+
title: "Masternode Registration Submitted",
63+
message:
64+
"Masternode registration submitted, your masternode will "
65+
"appear in the list after the tx is confirmed.\n\nTransaction"
66+
" ID: $txid",
67+
desktopPopRootNavigator: Util.isDesktop,
68+
maxWidth: Util.isDesktop ? 400 : null,
69+
),
70+
);
71+
}
4372
}
4473

4574
@override
@@ -155,11 +184,12 @@ class _MasternodesHomeViewState extends ConsumerState<MasternodesHomeView> {
155184
width: 20,
156185
height: 20,
157186
),
158-
onPressed: () {
159-
Navigator.of(context).pushNamed(
187+
onPressed: () async {
188+
final txid = await Navigator.of(context).pushNamed(
160189
CreateMasternodeView.routeName,
161190
arguments: widget.walletId,
162191
);
192+
_handleSuccessTxid(txid);
163193
},
164194
),
165195
),
@@ -199,14 +229,15 @@ class _MasternodesHomeViewState extends ConsumerState<MasternodesHomeView> {
199229
label: "Create Your First Masternode",
200230
horizontalContentPadding: 16,
201231
buttonHeight: Util.isDesktop ? .l : null,
202-
onPressed: () {
232+
onPressed: () async {
203233
if (Util.isDesktop) {
204-
_showDesktopCreateMasternodeDialog();
234+
await _showDesktopCreateMasternodeDialog();
205235
} else {
206-
Navigator.of(context).pushNamed(
236+
final txid = await Navigator.of(context).pushNamed(
207237
CreateMasternodeView.routeName,
208238
arguments: widget.walletId,
209239
);
240+
_handleSuccessTxid(txid);
210241
}
211242
},
212243
),

lib/pages/masternodes/sub_widgets/register_masternode_form.dart

Lines changed: 75 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,24 @@ import '../../../utilities/text_styles.dart';
1111
import '../../../utilities/util.dart';
1212
import '../../../wallets/isar/providers/wallet_info_provider.dart';
1313
import '../../../wallets/wallet/impl/firo_wallet.dart';
14+
import '../../../widgets/conditional_parent.dart';
1415
import '../../../widgets/desktop/primary_button.dart';
1516
import '../../../widgets/desktop/secondary_button.dart';
1617
import '../../../widgets/rounded_container.dart';
1718
import '../../../widgets/stack_dialog.dart';
1819
import '../../../widgets/textfields/adaptive_text_field.dart';
1920

2021
class RegisterMasternodeForm extends ConsumerStatefulWidget {
21-
const RegisterMasternodeForm({super.key, required this.firoWalletId});
22+
const RegisterMasternodeForm({
23+
super.key,
24+
required this.firoWalletId,
25+
required this.onRegistrationSuccess,
26+
});
2227

2328
final String firoWalletId;
2429

30+
final void Function(String) onRegistrationSuccess;
31+
2532
@override
2633
ConsumerState<RegisterMasternodeForm> createState() =>
2734
_RegisterMasternodeFormState();
@@ -53,11 +60,18 @@ class _RegisterMasternodeFormState
5360

5461
void _validate() {
5562
if (mounted) {
63+
final percent = double.tryParse(_operatorRewardController.text);
5664
setState(() {
5765
_enableCreateButton = [
58-
_ipAndPortController.text.trim().isNotEmpty,
66+
_ipAndPortController.text
67+
.trim()
68+
.split(":")
69+
.where((e) => e.isNotEmpty)
70+
.length ==
71+
2,
5972
_operatorPubKeyController.text.trim().isNotEmpty,
60-
_operatorRewardController.text.trim().isNotEmpty,
73+
percent != null && !percent.isNegative,
74+
percent != null && percent <= 100.0,
6175
_payoutAddressController.text.trim().isNotEmpty,
6276
].every((e) => e);
6377
});
@@ -70,11 +84,16 @@ class _RegisterMasternodeFormState
7084
final port = int.parse(parts[1]);
7185
final operatorPubKey = _operatorPubKeyController.text.trim();
7286
final votingAddress = _votingAddressController.text.trim();
73-
final operatorReward = _operatorRewardController.text.trim().isNotEmpty
74-
? (double.parse(_operatorRewardController.text.trim()) * 100).floor()
75-
: 0;
7687
final payoutAddress = _payoutAddressController.text.trim();
7788

89+
// according to https://github.com/cypherstack/stack_wallet/blob/c898a70f808ed5490b8dd23571f5f162d9e38158/lib/wallets/wallet/impl/firo_wallet.dart#L1064
90+
// this should be a percent of 10000
91+
final operatorPercent = double.parse(_operatorRewardController.text);
92+
final operatorReward = (10000 * (operatorPercent / 100)).round().clamp(
93+
0,
94+
10000,
95+
);
96+
7897
final wallet =
7998
ref.read(pWallets).getWallet(widget.firoWalletId) as FiroWallet;
8099

@@ -105,41 +124,33 @@ class _RegisterMasternodeFormState
105124
Exception? ex;
106125

107126
final txId = await showLoading(
108-
whileFuture: _registerMasternode(),
127+
whileFutureAlt: _registerMasternode,
109128
context: context,
110129
message: "Creating and submitting masternode registration...",
111130
delay: const Duration(seconds: 1),
112131
onException: (e) => ex = e,
113132
);
114133

115134
if (mounted) {
116-
final String title;
117-
String message;
118135
if (ex != null || txId == null) {
119-
message = ex?.toString().trim() ?? "Unknown error: txId=$txId";
136+
String message = ex?.toString().trim() ?? "Unknown error: txId=$txId";
120137
const exceptionPrefix = "Exception:";
121138
while (message.startsWith(exceptionPrefix) &&
122139
message.length > exceptionPrefix.length) {
123140
message = message.substring(exceptionPrefix.length).trim();
124141
}
125-
title = "Registration failed";
142+
await showDialog<void>(
143+
context: context,
144+
builder: (_) => StackOkDialog(
145+
title: "Registration failed",
146+
message: message,
147+
desktopPopRootNavigator: Util.isDesktop,
148+
maxWidth: Util.isDesktop ? 400 : null,
149+
),
150+
);
126151
} else {
127-
title = "Masternode Registration Submitted";
128-
message =
129-
"Masternode registration submitted, your masternode will "
130-
"appear in the list after the tx is confirmed.\n\nTransaction"
131-
" ID: $txId";
152+
widget.onRegistrationSuccess.call(txId);
132153
}
133-
134-
await showDialog<void>(
135-
context: context,
136-
builder: (_) => StackOkDialog(
137-
title: title,
138-
message: message,
139-
desktopPopRootNavigator: Util.isDesktop,
140-
maxWidth: Util.isDesktop ? 400 : null,
141-
),
142-
);
143154
}
144155
}).execute;
145156
}
@@ -180,26 +191,23 @@ class _RegisterMasternodeFormState
180191
mainAxisSize: MainAxisSize.min,
181192
crossAxisAlignment: CrossAxisAlignment.start,
182193
children: [
183-
Flexible(
184-
child: Row(
185-
mainAxisAlignment: MainAxisAlignment.center,
186-
children: [
187-
Flexible(
188-
child: RoundedContainer(
189-
color: infoColorBG,
190-
child: Padding(
191-
padding: const EdgeInsets.all(8.0),
192-
child: Text(
193-
infoMessage,
194-
style: STextStyles.w600_14(
195-
context,
196-
).copyWith(color: infoColor),
197-
),
194+
Row(
195+
children: [
196+
Expanded(
197+
child: RoundedContainer(
198+
color: infoColorBG,
199+
child: Padding(
200+
padding: const EdgeInsets.all(8.0),
201+
child: Text(
202+
infoMessage,
203+
style: STextStyles.w600_14(
204+
context,
205+
).copyWith(color: infoColor),
198206
),
199207
),
200208
),
201-
],
202-
),
209+
),
210+
],
203211
),
204212

205213
SizedBox(height: Util.isDesktop ? 24 : 16),
@@ -254,27 +262,32 @@ class _RegisterMasternodeFormState
254262
onChangedComprehensive: (_) => _validate(),
255263
),
256264

257-
Util.isDesktop ? const SizedBox(height: 32) : const Spacer(),
265+
Util.isDesktop
266+
? const SizedBox(height: 32)
267+
: const SizedBox(height: 16),
268+
if (!Util.isDesktop) const Spacer(),
258269

259-
Row(
260-
children: [
261-
Expanded(
262-
child: SecondaryButton(
263-
label: "Cancel",
264-
onPressed: Navigator.of(context).pop,
265-
buttonHeight: Util.isDesktop ? .l : null,
266-
),
267-
),
268-
SizedBox(width: Util.isDesktop ? 24 : 16),
269-
Expanded(
270-
child: PrimaryButton(
271-
label: "Create",
272-
enabled: _enableCreateButton,
273-
onPressed: _enableCreateButton ? _register : null,
274-
buttonHeight: Util.isDesktop ? .l : null,
270+
ConditionalParent(
271+
condition: Util.isDesktop,
272+
builder: (child) => Row(
273+
children: [
274+
Expanded(
275+
child: SecondaryButton(
276+
label: "Cancel",
277+
onPressed: Navigator.of(context).pop,
278+
buttonHeight: .l,
279+
),
275280
),
276-
),
277-
],
281+
const SizedBox(width: 24),
282+
Expanded(child: child),
283+
],
284+
),
285+
child: PrimaryButton(
286+
label: "Create",
287+
enabled: _enableCreateButton,
288+
onPressed: _enableCreateButton ? _register : null,
289+
buttonHeight: Util.isDesktop ? .l : null,
290+
),
278291
),
279292
],
280293
);

lib/wallets/wallet/impl/firo_wallet.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class MasternodeInfo {
3434
final String collateralHash;
3535
final int collateralIndex;
3636
final String collateralAddress;
37-
final int operatorReward;
37+
final double operatorReward;
3838
final String serviceAddr;
3939
final int servicePort;
4040
final int registeredHeight;
@@ -1181,7 +1181,7 @@ class FiroWallet<T extends ElectrumXCurrencyInterface> extends Bip39HDWallet<T>
11811181
collateralHash: info["collateralHash"] as String,
11821182
collateralIndex: info["collateralIndex"] as int,
11831183
collateralAddress: info["collateralAddress"] as String,
1184-
operatorReward: info["operatorReward"] as int,
1184+
operatorReward: double.parse(info["operatorReward"].toString()),
11851185
serviceAddr: (info["state"]["service"] as String).substring(
11861186
0,
11871187
(info["state"]["service"] as String).lastIndexOf(":"),

0 commit comments

Comments
 (0)