Merge pull request #1449 from levoncrypto/masternode-ui
What changed, and why it matters
This commit fixes the masternode status display in the Firo wallet. Previously, the UI only showed a masternode as either 'ACTIVE' or 'REVOKED' based on a single check. Now it correctly distinguishes three states: active, banned, and revoked. This is a user-interface bug fix with no apparent security impact.
No security action required. Treat as routine UI bug fix.
Security signals we found
No security-relevant signals detected in diff
Change is UI/status labeling only
No input validation, cryptography, authentication, or authorization changes
Evidence from the diff
The patch introduces a MasternodeStatus enum (active/banned/revoked) and a computed status getter on MasternodeInfo. Logic now checks revocationReason != 0 for revoked, poseBanHeight != -1 for banned, and otherwise active. The UI color badge and label are updated accordingly. The change is purely presentational/status classification.
Changed components
lib/pages/masternodes/sub_widgets/masternodes_list.dartlib/wallets/wallet/impl/firo_wallet.dartInspect captured patch +30 / −13
### lib/pages/masternodes/sub_widgets/masternodes_list.dart
@@ -68,16 +68,15 @@ class _MasternodeCard extends StatelessWidget {
),
);
} else {
- await Navigator.of(
- context,
- ).pushNamed(MasternodeDetailsView.routeName, arguments: node);
+ await Navigator.of(context)
+ .pushNamed(MasternodeDetailsView.routeName, arguments: node);
}
}
@override
Widget build(BuildContext context) {
final stack = Theme.of(context).extension<StackColors>()!;
- final isActive = node.revocationReason == 0;
+ final status = node.status;
return RoundedWhiteContainer(
padding: const EdgeInsets.all(16),
@@ -97,9 +96,8 @@ class _MasternodeCard extends StatelessWidget {
const SizedBox(height: 2),
Text(
"Last paid height: ${node.lastPaidHeight}",
- style: STextStyles.baseXS(
- context,
- ).copyWith(color: stack.textSubtitle1),
+ style: STextStyles.baseXS(context)
+ .copyWith(color: stack.textSubtitle1),
),
],
),
@@ -108,14 +106,17 @@ class _MasternodeCard extends StatelessWidget {
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
- color: isActive ? stack.accentColorGreen : stack.accentColorRed,
+ color: switch (status) {
+ MasternodeStatus.active => stack.accentColorGreen,
+ MasternodeStatus.banned => stack.accentColorOrange,
+ MasternodeStatus.revoked => stack.accentColorRed,
+ },
borderRadius: BorderRadius.circular(8),
),
child: Text(
- isActive ? "ACTIVE" : "REVOKED",
- style: STextStyles.w600_12(
- context,
- ).copyWith(color: stack.textWhite),
+ status.label,
+ style: STextStyles.w600_12(context)
+ .copyWith(color: stack.textWhite),
),
),
],
### lib/wallets/wallet/impl/firo_wallet.dart
@@ -32,6 +32,16 @@ import '../wallet_mixin_interfaces/extended_keys_interface.dart';
import '../wallet_mixin_interfaces/spark_interface.dart';
import 'firo_transaction_type.dart';
+enum MasternodeStatus {
+ active("ACTIVE"),
+ banned("BANNED"),
+ revoked("REVOKED");
+
+ const MasternodeStatus(this.label);
+
+ final String label;
+}
+
class MasternodeInfo {
final String proTxHash;
final String collateralHash;
@@ -71,11 +81,17 @@ class MasternodeInfo {
required this.pubKeyOperator,
});
+ MasternodeStatus get status {
+ if (revocationReason != 0) return MasternodeStatus.revoked;
+ if (poseBanHeight != -1) return MasternodeStatus.banned;
+ return MasternodeStatus.active;
+ }
+
Map<String, String> pretty() {
return {
"ProTx Hash": proTxHash,
"IP:Port": "$serviceAddr:$servicePort",
- "Status": revocationReason == 0 ? "Active" : "Revoked",
+ "Status": status.label,
"Registered Height": registeredHeight.toString(),
"Last Paid Height": lastPaidHeight.toString(),
"Payout Address": payoutAddress,Why this scored 18/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.