From 6487c9fbc0947b5d7d495278c617db53a4f64fc3 Mon Sep 17 00:00:00 2001 From: Santiago Gonzalez Date: Tue, 21 Oct 2025 17:00:15 +0200 Subject: [PATCH 1/2] add better minipool status management + display minipool address --- .../ui/src/components/Setup/MinipoolCard.tsx | 47 ++++++++++++++++--- build/ui/src/components/Setup/minipool.css | 6 +++ build/ui/src/utils/Utils.ts | 5 ++ 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/build/ui/src/components/Setup/MinipoolCard.tsx b/build/ui/src/components/Setup/MinipoolCard.tsx index c3f873c..498e830 100644 --- a/build/ui/src/components/Setup/MinipoolCard.tsx +++ b/build/ui/src/components/Setup/MinipoolCard.tsx @@ -1,10 +1,12 @@ import React from "react"; -import { Card, CardContent, Typography, Chip, Button } from "@mui/material"; -import { Minipool } from "../../types/MinipoolStatus"; -import { toEtherString } from "../../utils/Utils"; import OpenInNewIcon from "@mui/icons-material/OpenInNew"; -import "./minipool.css"; +import { Button, Card, CardContent, Chip, Tooltip, Typography } from "@mui/material"; +import CopyToClipboardButton from "../Buttons/CopyToClipboardButton"; +import { Minipool } from "../../types/MinipoolStatus"; +import { ethBalanceGreaterThanMinStake, shortenAddress, toEtherString } from "../../utils/Utils"; import ImportToSignerDialog from "./ImportToSignerDialog"; +import "./minipool.css"; + function MinipoolCard({ data, @@ -17,6 +19,7 @@ function MinipoolCard({ }): JSX.Element { const [importToSignerDialogOpen, setImportToSignerDialogOpen] = React.useState(false); + const [showAddress, setShowAddress] = React.useState(false); const backgroundColor = data.status.status === "Staking" @@ -25,6 +28,24 @@ function MinipoolCard({ ? "#E57373" : "#FFB74D"; + const validatorStatus = data.finalised + ? "Exited" + : (!data.validator.index && data.status.status === "Staking") + ? "Enqueued" + : (data.validator.active + ? "Active" + : (data.status.status === "Staking" && ethBalanceGreaterThanMinStake(data.balances.eth) + ? "Ready to Close" + : "Inactive" + ) + ); + const validatorStatusColor = + data.finalised || data.validator.active + ? "#81C784" + : (data.status.status === "Prelaunch" || ["Enqueued", "Ready to Close"].includes(validatorStatus)) + ? "#FFC107" + : "#E57373"; + return (
- +
+ + setShowAddress(!showAddress)} + sx={{ cursor: 'pointer' }} + /> + + +
diff --git a/build/ui/src/components/Setup/minipool.css b/build/ui/src/components/Setup/minipool.css index 2736bc6..2d08b3c 100644 --- a/build/ui/src/components/Setup/minipool.css +++ b/build/ui/src/components/Setup/minipool.css @@ -39,11 +39,17 @@ margin-bottom: 0.5rem; } +.chip-with-clipboard-container { + display: flex; + align-items: center; +} + .explorer-button-container { margin-top: 1rem; } .minipool-ether { + margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; font-weight: bold !important; } diff --git a/build/ui/src/utils/Utils.ts b/build/ui/src/utils/Utils.ts index 4476538..1762f6b 100644 --- a/build/ui/src/utils/Utils.ts +++ b/build/ui/src/utils/Utils.ts @@ -41,4 +41,9 @@ export function enoughEthBalance( return is8EthPool ? ethBalance >= minimum8Eth : ethBalance >= minimum16Eth; } +export function ethBalanceGreaterThanMinStake(ethBalance: number): boolean { + const minStake = BigInt(32 * 10 ** 18); + return BigInt(ethBalance) > minStake; +} + export const escapeNewLine = (text: string) => text.replace(/(\\n)/g, "\n"); From 8234ce93f8aea8e8651e979f5aae5df31761b5cb Mon Sep 17 00:00:00 2001 From: Santiago Gonzalez Date: Fri, 24 Oct 2025 05:08:13 +0200 Subject: [PATCH 2/2] refactor minipool+validator status logic for better readability and maintainability --- .../ui/src/components/Setup/MinipoolCard.tsx | 160 ++++++++++++++---- 1 file changed, 131 insertions(+), 29 deletions(-) diff --git a/build/ui/src/components/Setup/MinipoolCard.tsx b/build/ui/src/components/Setup/MinipoolCard.tsx index 498e830..ed8673f 100644 --- a/build/ui/src/components/Setup/MinipoolCard.tsx +++ b/build/ui/src/components/Setup/MinipoolCard.tsx @@ -7,6 +7,129 @@ import { ethBalanceGreaterThanMinStake, shortenAddress, toEtherString } from ".. import ImportToSignerDialog from "./ImportToSignerDialog"; import "./minipool.css"; +enum MinipoolStatus { + STAKING = "Staking", + DISSOLVED = "Dissolved", + PRELAUNCH = "Prelaunch", + FINALISED = "Finalised" +} + +enum ValidatorStatus { + EXITED = "Exited", + ENQUEUED = "Enqueued", + ACTIVE = "Active", + READY_TO_CLOSE = "Ready to Close", + INACTIVE = "Inactive" +} + +// Color theme constants +const COLOR_THEME = { + SUCCESS: "#81C784", // Green + WARNING: "#FFC107", // Amber + ERROR: "#E57373", // Red + INFO: "#FFB74D" // Orange +} as const; + +// Status information interface +interface StatusInfo { + status: string; + color: string; +} + +// Validator Status Service +class ValidatorStatusService { + /** + * Determines the minipool status and returns status info + */ + getMinipoolStatusInfo(minipoolData: Minipool): StatusInfo { + const status = this.determineMinipoolStatus(minipoolData); + const color = this.getMinipoolStatusColor(status); + return { status, color }; + } + + /** + * Determines the validator status and returns status info + */ + getValidatorStatusInfo(minipoolData: Minipool): StatusInfo { + const status = this.determineValidatorStatus(minipoolData); + const color = this.getValidatorStatusColor(status, minipoolData); + return { status, color }; + } + + /** + * Determines the minipool status based on finalised state + */ + private determineMinipoolStatus(minipoolData: Minipool): string { + return minipoolData.finalised ? MinipoolStatus.FINALISED : minipoolData.status.status; + } + + /** + * Determines the validator status with priority-based logic + */ + private determineValidatorStatus(minipoolData: Minipool): string { + // Priority 1: Check if finalised + if (minipoolData.finalised) { + return ValidatorStatus.EXITED; + } + + // Priority 2: Check if enqueued (staking but no validator index) + if (minipoolData.status.status === MinipoolStatus.STAKING && !minipoolData.validator.index) { + return ValidatorStatus.ENQUEUED; + } + + // Priority 3: Check if validator is active + if (minipoolData.validator.active) { + return ValidatorStatus.ACTIVE; + } + + // Priority 4: Check if ready to close (staking with sufficient balance) + if (minipoolData.status.status === MinipoolStatus.STAKING && + ethBalanceGreaterThanMinStake(minipoolData.balances.eth)) { + return ValidatorStatus.READY_TO_CLOSE; + } + + // Default: Inactive + return ValidatorStatus.INACTIVE; + } + + /** + * Gets the color for minipool status + */ + private getMinipoolStatusColor(status: string): string { + switch (status) { + case MinipoolStatus.STAKING: + return COLOR_THEME.SUCCESS; + case MinipoolStatus.DISSOLVED: + return COLOR_THEME.ERROR; + case MinipoolStatus.FINALISED: + return COLOR_THEME.WARNING; + default: + return COLOR_THEME.INFO; + } + } + + /** + * Gets the color for validator status + */ + private getValidatorStatusColor(validatorStatus: string, minipoolData: Minipool): string { + // Success color for finalised or active validators + if (minipoolData.finalised || minipoolData.validator.active) { + return COLOR_THEME.SUCCESS; + } + + // Warning color for prelaunch, enqueued, or ready to close + if (minipoolData.status.status === MinipoolStatus.PRELAUNCH || + [ValidatorStatus.ENQUEUED, ValidatorStatus.READY_TO_CLOSE].includes(validatorStatus as ValidatorStatus)) { + return COLOR_THEME.WARNING; + } + + // Error color for inactive + return COLOR_THEME.ERROR; + } +}; + +// Initialize status service +const statusService = new ValidatorStatusService(); function MinipoolCard({ data, @@ -20,31 +143,10 @@ function MinipoolCard({ const [importToSignerDialogOpen, setImportToSignerDialogOpen] = React.useState(false); const [showAddress, setShowAddress] = React.useState(false); - - const backgroundColor = - data.status.status === "Staking" - ? "#81C784" - : data.status.status === "Dissolved" - ? "#E57373" - : "#FFB74D"; - - const validatorStatus = data.finalised - ? "Exited" - : (!data.validator.index && data.status.status === "Staking") - ? "Enqueued" - : (data.validator.active - ? "Active" - : (data.status.status === "Staking" && ethBalanceGreaterThanMinStake(data.balances.eth) - ? "Ready to Close" - : "Inactive" - ) - ); - const validatorStatusColor = - data.finalised || data.validator.active - ? "#81C784" - : (data.status.status === "Prelaunch" || ["Enqueued", "Ready to Close"].includes(validatorStatus)) - ? "#FFC107" - : "#E57373"; + + // Get status information using the service + const minipoolStatusInfo = statusService.getMinipoolStatusInfo(data); + const validatorStatusInfo = statusService.getValidatorStatusInfo(data); return (