diff --git a/apps/wallet-dashboard/components/Dialogs/StakedDetails/StakedDetailsDialog.tsx b/apps/wallet-dashboard/components/Dialogs/StakedDetails/StakedDetailsDialog.tsx
index 5ae0b5eda36..15e557bea61 100644
--- a/apps/wallet-dashboard/components/Dialogs/StakedDetails/StakedDetailsDialog.tsx
+++ b/apps/wallet-dashboard/components/Dialogs/StakedDetails/StakedDetailsDialog.tsx
@@ -1,36 +1,35 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0
-import React, { useMemo } from 'react';
+import React from 'react';
import {
- useGetValidatorsApy,
ExtendedDelegatedStake,
+ formatPercentageDisplay,
ImageIcon,
ImageIconSize,
useFormatCoin,
- formatPercentageDisplay,
} from '@iota/core';
import {
- Dialog,
- DialogBody,
- DialogContent,
- DialogPosition,
- Header,
+ Badge,
+ BadgeType,
Button,
ButtonType,
Card,
CardBody,
CardImage,
CardType,
- Panel,
- KeyValueInfo,
- Badge,
- BadgeType,
+ Dialog,
+ DialogBody,
+ DialogContent,
+ DialogPosition,
Divider,
+ Header,
InfoBox,
InfoBoxStyle,
InfoBoxType,
+ KeyValueInfo,
LoadingIndicator,
+ Panel,
} from '@iota/apps-ui-kit';
import { Warning } from '@iota/ui-icons';
import { useUnstakeTransaction } from '@/hooks';
@@ -40,11 +39,14 @@ import {
useSignAndExecuteTransaction,
} from '@iota/dapp-kit';
import { formatAddress, IOTA_TYPE_ARG } from '@iota/iota-sdk/utils';
+import { useValidatorInfo } from '@/hooks';
+
interface StakeDialogProps {
stakedDetails: ExtendedDelegatedStake;
showActiveStatus?: boolean;
handleClose: () => void;
}
+
export function StakedDetailsDialog({
handleClose,
stakedDetails,
@@ -53,46 +55,22 @@ export function StakedDetailsDialog({
const account = useCurrentAccount();
const totalStake = BigInt(stakedDetails?.principal || 0n);
const validatorAddress = stakedDetails?.validatorAddress;
- const {
- data: system,
- isPending: loadingValidators,
- isError: errorValidators,
- } = useIotaClientQuery('getLatestIotaSystemState');
- const { data: rollingAverageApys } = useGetValidatorsApy();
- const { apy, isApyApproxZero } = rollingAverageApys?.[validatorAddress] ?? {
- apy: null,
- };
+ const { isPending: loadingValidators, isError: errorValidators } = useIotaClientQuery(
+ 'getLatestIotaSystemState',
+ );
const iotaEarned = BigInt(stakedDetails?.estimatedReward || 0n);
const [iotaEarnedFormatted, iotaEarnedSymbol] = useFormatCoin(iotaEarned, IOTA_TYPE_ARG);
const [totalStakeFormatted, totalStakeSymbol] = useFormatCoin(totalStake, IOTA_TYPE_ARG);
+ const { name, commission, newValidator, isAtRisk, apy, isApyApproxZero } =
+ useValidatorInfo(validatorAddress);
+
const { data: unstakeData } = useUnstakeTransaction(
stakedDetails.stakedIotaId,
account?.address || '',
);
const { mutateAsync: signAndExecuteTransaction } = useSignAndExecuteTransaction();
- // flag if the validator is at risk of being removed from the active set
- const isAtRisk = system?.atRiskValidators.some((item) => item[0] === validatorAddress);
-
- const validatorSummary = useMemo(() => {
- if (!system) return null;
-
- return (
- system.activeValidators.find(
- (validator) => validator.iotaAddress === validatorAddress,
- ) || null
- );
- }, [validatorAddress, system]);
-
- const validatorName = validatorSummary?.name || '';
- const stakingPoolActivationEpoch = Number(validatorSummary?.stakingPoolActivationEpoch || 0);
- const currentEpoch = Number(system?.epoch || 0);
- const commission = validatorSummary ? Number(validatorSummary.commissionRate) / 100 : 0;
-
- // flag as new validator if the validator was activated in the last epoch
- // for genesis validators, this will be false
- const newValidator = currentEpoch - stakingPoolActivationEpoch <= 1 && currentEpoch !== 0;
const subtitle = showActiveStatus ? (
{formatAddress(validatorAddress)}
@@ -153,16 +131,12 @@ export function StakedDetailsDialog({
-
+
diff --git a/apps/wallet-dashboard/components/Dialogs/Staking/StakeDialog.tsx b/apps/wallet-dashboard/components/Dialogs/Staking/StakeDialog.tsx
index d7e9d1cbc75..afa705ff4a0 100644
--- a/apps/wallet-dashboard/components/Dialogs/Staking/StakeDialog.tsx
+++ b/apps/wallet-dashboard/components/Dialogs/Staking/StakeDialog.tsx
@@ -119,28 +119,37 @@ function StakeDialog({
});
}
+ const title = {
+ [Step.SelectValidator]: 'Select Validator',
+ [Step.EnterAmount]: 'Enter Amount',
+ };
+
return (
);
diff --git a/apps/wallet-dashboard/components/Dialogs/Staking/views/SelectValidatorView.tsx b/apps/wallet-dashboard/components/Dialogs/Staking/views/SelectValidatorView.tsx
index 25dbeb276cf..ac3bdeb1a5f 100644
--- a/apps/wallet-dashboard/components/Dialogs/Staking/views/SelectValidatorView.tsx
+++ b/apps/wallet-dashboard/components/Dialogs/Staking/views/SelectValidatorView.tsx
@@ -2,7 +2,19 @@
// SPDX-License-Identifier: Apache-2.0
import React from 'react';
-import { Button } from '@/components';
+import { ImageIcon, ImageIconSize, formatPercentageDisplay } from '@iota/core';
+import {
+ Card,
+ CardBody,
+ CardImage,
+ CardAction,
+ CardActionType,
+ CardType,
+ Badge,
+ BadgeType,
+} from '@iota/apps-ui-kit';
+import { formatAddress } from '@iota/iota-sdk/utils';
+import { useValidatorInfo } from '@/hooks';
interface SelectValidatorViewProps {
validators: string[];
@@ -11,17 +23,47 @@ interface SelectValidatorViewProps {
function SelectValidatorView({ validators, onSelect }: SelectValidatorViewProps): JSX.Element {
return (
-
-
Select Validator
-
- {validators.map((validator) => (
-
- ))}
-
+
+ {validators.map((validator) => (
+
+ ))}
);
}
+function Validator({
+ address,
+ showActiveStatus,
+ onClick,
+}: {
+ address: string;
+ showActiveStatus?: boolean;
+ onClick: (address: string) => void;
+}) {
+ const { name, newValidator, isAtRisk, apy, isApyApproxZero } = useValidatorInfo(address);
+
+ const subtitle = showActiveStatus ? (
+
+ {formatAddress(address)}
+ {newValidator && }
+ {isAtRisk && }
+
+ ) : (
+ formatAddress(address)
+ );
+ return (
+
onClick(address)}>
+
+
+
+
+
+
+ );
+}
+
export default SelectValidatorView;
diff --git a/apps/wallet-dashboard/hooks/index.ts b/apps/wallet-dashboard/hooks/index.ts
index 07ccfe796f8..96072fcc720 100644
--- a/apps/wallet-dashboard/hooks/index.ts
+++ b/apps/wallet-dashboard/hooks/index.ts
@@ -9,3 +9,4 @@ export * from './useSendCoinTransaction';
export * from './useCreateSendAssetTransaction';
export * from './useGetCurrentEpochStartTimestamp';
export * from './useTimelockedUnstakeTransaction';
+export * from './useValidatorInfo';
diff --git a/apps/wallet-dashboard/hooks/useValidatorInfo.tsx b/apps/wallet-dashboard/hooks/useValidatorInfo.tsx
new file mode 100644
index 00000000000..214dbe20e0a
--- /dev/null
+++ b/apps/wallet-dashboard/hooks/useValidatorInfo.tsx
@@ -0,0 +1,46 @@
+// Copyright (c) 2024 IOTA Stiftung
+// SPDX-License-Identifier: Apache-2.0
+import { useMemo } from 'react';
+import { useIotaClientQuery } from '@iota/dapp-kit';
+import { useGetValidatorsApy } from '@iota/core';
+
+export function useValidatorInfo(validatorAddress: string) {
+ const { data: system } = useIotaClientQuery('getLatestIotaSystemState');
+ const { data: rollingAverageApys } = useGetValidatorsApy();
+
+ const currentEpoch = Number(system?.epoch || 0);
+
+ const validatorSummary = useMemo(() => {
+ if (!system) return null;
+
+ return (
+ system.activeValidators.find(
+ (validator) => validator.iotaAddress === validatorAddress,
+ ) || null
+ );
+ }, [validatorAddress, system]);
+
+ const stakingPoolActivationEpoch = Number(validatorSummary?.stakingPoolActivationEpoch || 0);
+
+ // flag as new validator if the validator was activated in the last epoch
+ // for genesis validators, this will be false
+ const newValidator = currentEpoch - stakingPoolActivationEpoch <= 1 && currentEpoch !== 0;
+
+ // flag if the validator is at risk of being removed from the active set
+ const isAtRisk = system?.atRiskValidators.some((item) => item[0] === validatorAddress);
+
+ const { apy, isApyApproxZero } = rollingAverageApys?.[validatorAddress] ?? {
+ apy: null,
+ };
+
+ return {
+ validatorSummary,
+ name: validatorSummary?.name || '',
+ stakingPoolActivationEpoch,
+ commission: validatorSummary ? Number(validatorSummary.commissionRate) / 100 : 0,
+ newValidator,
+ isAtRisk,
+ apy,
+ isApyApproxZero,
+ };
+}