fix(firo): desktop/mobile ui branching for masternode registrations
What changed, and why it matters
This commit fixes UI layout and navigation bugs in the Firo masternode registration flow for desktop and mobile. It removes an unnecessary visual wrapper on desktop, simplifies a button text style, and—most importantly—corrects the post-transaction navigation so the masternode creation screen appears properly on desktop inside a dialog and on mobile via page navigation. It also removes a special-case refresh for Firo wallets, treating all wallets the same after sending. There is no direct security vulnerability visible in the diff; it reads as a routine UI/UX bug fix.
Treat as a normal UI/UX fix. No immediate security action required. If the Firo refresh removal is concerning, verify that wallet.refresh() handles Firo errors equivalently elsewhere, but the diff itself does not indicate a vulnerability.
Security signals we found
No cryptographic, authentication, or authorization changes
No input validation changes
No network or RPC changes
No transaction construction logic changes
UI-only branching and styling adjustments
Removal of Firo-specific post-send refresh exception handling
Evidence from the diff
The patch adjusts three Dart files in the Stack Wallet Flutter app. In create_masternode_view.dart it removes a Material/SizedBox wrapper around the desktop dialog content, leaving only the SizedBox. In masternodes_home_view.dart it drops an explicit button text color override. In confirm_transaction_view.dart it removes a Firo-specific synchronous refresh with error logging and uses the same unawaited(wallet.refresh()) path as other wallets. It then restructures the masternode-success navigation: on desktop it pops to routeOnSuccessName and shows CreateMasternodeView inside an SDialog; on mobile it pops and pushes the named route with arguments. The changes appear to be UI branching and cleanup rather than a security fix.
Changed components
lib/pages/masternodes/create_masternode_view.dartlib/pages/masternodes/masternodes_home_view.dartlib/pages/send_view/confirm_transaction_view.dartInspect captured patch +62 / −76
diff --git a/lib/pages/masternodes/create_masternode_view.dart b/lib/pages/masternodes/create_masternode_view.dart
index d3f8cba..4355273 100644
--- a/lib/pages/masternodes/create_masternode_view.dart
+++ b/lib/pages/masternodes/create_masternode_view.dart
@@ -38,40 +38,36 @@ class _CreateMasternodeDialogState extends ConsumerState<CreateMasternodeView> {
Widget build(BuildContext context) {
return ConditionalParent(
condition: Util.isDesktop,
- builder: (child) => Material(
- color: Theme.of(context).extension<StackColors>()!.popupBG,
- borderRadius: BorderRadius.circular(20),
- child: SizedBox(
- width: 660,
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.stretch,
- mainAxisSize: MainAxisSize.min,
- children: [
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- Padding(
- padding: const EdgeInsets.only(left: 32),
- child: Text(
- "Create masternode",
- style: STextStyles.desktopH3(context),
- ),
- ),
- const DesktopDialogCloseButton(),
- ],
- ),
- Flexible(
- child: Padding(
- padding: const EdgeInsets.only(
- left: 32,
- bottom: 32,
- right: 32,
+ builder: (child) => SizedBox(
+ width: 660,
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Padding(
+ padding: const EdgeInsets.only(left: 32),
+ child: Text(
+ "Create masternode",
+ style: STextStyles.desktopH3(context),
),
- child: child,
),
+ const DesktopDialogCloseButton(),
+ ],
+ ),
+ Flexible(
+ child: Padding(
+ padding: const EdgeInsets.only(
+ left: 32,
+ bottom: 32,
+ right: 32,
+ ),
+ child: child,
),
- ],
- ),
+ ),
+ ],
),
),
child: ConditionalParent(
diff --git a/lib/pages/masternodes/masternodes_home_view.dart b/lib/pages/masternodes/masternodes_home_view.dart
index a9b4271..ae364dd 100644
--- a/lib/pages/masternodes/masternodes_home_view.dart
+++ b/lib/pages/masternodes/masternodes_home_view.dart
@@ -161,10 +161,7 @@ class _MasternodesHomeViewState extends ConsumerState<MasternodesHomeView>
.getPrimaryEnabledButtonStyle(ctx),
child: Text(
"Register",
- style: STextStyles.button(ctx).copyWith(
- color:
- Theme.of(ctx).extension<StackColors>()!.buttonTextPrimary,
- ),
+ style: STextStyles.button(ctx),
),
onPressed: () => Navigator.of(ctx).pop(true),
),
diff --git a/lib/pages/send_view/confirm_transaction_view.dart b/lib/pages/send_view/confirm_transaction_view.dart
index 60c15ef..078cafd 100644
--- a/lib/pages/send_view/confirm_transaction_view.dart
+++ b/lib/pages/send_view/confirm_transaction_view.dart
@@ -490,19 +490,7 @@ class _ConfirmTransactionViewState
unawaited(ref.read(pCurrentTokenWallet)!.refresh());
}
} else {
- if (wallet is FiroWallet) {
- try {
- await wallet.refresh();
- } catch (e, s) {
- Logging.instance.w(
- "Post-send wallet refresh failed: $e",
- error: e,
- stackTrace: s,
- );
- }
- } else {
- unawaited(wallet.refresh());
- }
+ unawaited(wallet.refresh());
}
widget.onSuccess.call();
@@ -558,36 +546,41 @@ class _ConfirmTransactionViewState
);
} else {
navigatedToMN = true;
- final navigator = Navigator.of(context);
- navigator.popUntil(
- ModalRoute.withName(routeOnSuccessName),
- );
- final dialogContext = navigator.context;
- if (!dialogContext.mounted) {
- return;
- }
- if (Util.isDesktop) {
- await showDialog<Object>(
- context: dialogContext,
- barrierDismissible: true,
- builder: (ctx) => SDialog(
- child: CreateMasternodeView(
- firoWalletId: walletId,
- collateralTxid: confirmedTx.txid!,
- collateralVout: collateralVout,
- collateralAddress: mnRecipient.address,
- ),
- ),
+ if (isDesktop) {
+ Navigator.of(context).popUntil(
+ ModalRoute.withName(routeOnSuccessName),
);
+ if (context.mounted) {
+ unawaited(
+ showDialog<void>(
+ context: context,
+ barrierDismissible: true,
+ builder: (_) => SDialog(
+ child: CreateMasternodeView(
+ firoWalletId: walletId,
+ collateralTxid: confirmedTx.txid!,
+ collateralVout: collateralVout,
+ collateralAddress: mnRecipient.address,
+ ),
+ ),
+ ),
+ );
+ }
} else {
- await navigator.pushNamed(
- CreateMasternodeView.routeName,
- arguments: {
- 'walletId': walletId,
- 'collateralTxid': confirmedTx.txid!,
- 'collateralVout': collateralVout,
- 'collateralAddress': mnRecipient.address,
- },
+ final navigator = Navigator.of(context);
+ navigator.popUntil(
+ ModalRoute.withName(routeOnSuccessName),
+ );
+ unawaited(
+ navigator.pushNamed(
+ CreateMasternodeView.routeName,
+ arguments: {
+ 'walletId': walletId,
+ 'collateralTxid': confirmedTx.txid!,
+ 'collateralVout': collateralVout,
+ 'collateralAddress': mnRecipient.address,
+ },
+ ),
);
}
}
Why this scored 19/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.