diff --git a/apps/wallet-dashboard/components/dialogs/staking/views/Validator.tsx b/apps/core/src/components/Validator.tsx similarity index 63% rename from apps/wallet-dashboard/components/dialogs/staking/views/Validator.tsx rename to apps/core/src/components/Validator.tsx index a76ed05db57..3161fe8a812 100644 --- a/apps/wallet-dashboard/components/dialogs/staking/views/Validator.tsx +++ b/apps/core/src/components/Validator.tsx @@ -1,6 +1,7 @@ -// Copyright (c) 2024 IOTA Stiftung +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { ImageIcon, ImageIconSize, formatPercentageDisplay, useValidatorInfo } from '@iota/core'; +import { ImageIcon, ImageIconSize, formatPercentageDisplay, useValidatorInfo } from '../'; import { Card, CardBody, @@ -10,24 +11,28 @@ import { CardType, Badge, BadgeType, + ImageShape, + Skeleton, } from '@iota/apps-ui-kit'; import { formatAddress } from '@iota/iota-sdk/utils'; interface ValidatorProps { - isSelected: boolean; + isSelected?: boolean; address: string; + type?: CardType; showActiveStatus?: boolean; - onClick?: (address: string) => void; - showAction?: boolean; - activeEpoch?: string; + onClick?: () => void; + showApy?: boolean; + activeEpoch?: number; } export function Validator({ address, - showActiveStatus, + type, + showActiveStatus = false, onClick, isSelected, - showAction = true, + showApy = true, activeEpoch, }: ValidatorProps) { const { @@ -38,10 +43,27 @@ export function Validator({ isApyApproxZero, validatorSummary, system, + isPendingValidators, } = useValidatorInfo({ validatorAddress: address, }); + if (isPendingValidators) { + return ( + + + + +
+ + +
+
+ +
+
+ ); + } // for inactive validators, show the epoch number const fallBackText = activeEpoch ? `Staked ${Number(system?.epoch) - Number(activeEpoch)} epochs ago` @@ -58,11 +80,8 @@ export function Validator({ ) : ( formatAddress(address) ); - - const handleClick = onClick ? () => onClick(address) : undefined; - return ( - + - {showAction && ( + {showApy && ( , null>; - renderValidatorLogo: RenderValidatorLogo; renderExplorerLink: RenderExplorerLink; } @@ -25,7 +24,6 @@ export function TransactionReceipt({ txn, activeAddress, summary, - renderValidatorLogo, renderExplorerLink, }: TransactionReceiptProps) { const { events } = txn; @@ -49,7 +47,6 @@ export function TransactionReceipt({ activeAddress={activeAddress} event={stakeTypeTransaction} gasSummary={summary?.gas} - renderValidatorLogo={renderValidatorLogo} renderExplorerLink={renderExplorerLink} /> ) : null} @@ -60,7 +57,6 @@ export function TransactionReceipt({ event={unstakeTypeTransaction} gasSummary={summary?.gas} renderExplorerLink={renderExplorerLink} - renderValidatorLogo={renderValidatorLogo} /> ) : null} diff --git a/apps/core/src/components/transaction/details/StakeTransactionDetails.tsx b/apps/core/src/components/transaction/details/StakeTransactionDetails.tsx index 57f7c62deea..47182a18668 100644 --- a/apps/core/src/components/transaction/details/StakeTransactionDetails.tsx +++ b/apps/core/src/components/transaction/details/StakeTransactionDetails.tsx @@ -1,19 +1,20 @@ // Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +import { CardType } from '@iota/apps-ui-kit'; import { IotaEvent } from '@iota/iota-sdk/client'; import { formatPercentageDisplay, getStakeDetailsFromEvent } from '../../../utils'; import { useGetValidatorsApy } from '../../../hooks'; import { TransactionAmount } from '../amount'; import { StakeTransactionInfo } from '../info'; import { IOTA_TYPE_ARG } from '@iota/iota-sdk/utils'; -import type { GasSummaryType, RenderExplorerLink, RenderValidatorLogo } from '../../../types'; +import { Validator } from '../../../'; +import type { GasSummaryType, RenderExplorerLink } from '../../../types'; interface StakeTransactionDetailsProps { event: IotaEvent; activeAddress: string | null; renderExplorerLink: RenderExplorerLink; - renderValidatorLogo: RenderValidatorLogo; gasSummary?: GasSummaryType; } @@ -21,7 +22,6 @@ export function StakeTransactionDetails({ event, gasSummary, activeAddress, - renderValidatorLogo: ValidatorLogo, renderExplorerLink, }: StakeTransactionDetailsProps) { const { stakedAmount, validatorAddress, epoch } = getStakeDetailsFromEvent(event); @@ -34,10 +34,11 @@ export function StakeTransactionDetails({ return (
{validatorAddress && ( - )} diff --git a/apps/core/src/components/transaction/info/UnstakeTransactionInfo.tsx b/apps/core/src/components/transaction/info/UnstakeTransactionInfo.tsx index f31705966ed..932fa20d5fc 100644 --- a/apps/core/src/components/transaction/info/UnstakeTransactionInfo.tsx +++ b/apps/core/src/components/transaction/info/UnstakeTransactionInfo.tsx @@ -5,15 +5,14 @@ import { TransactionAmount } from '../amount'; import type { IotaEvent } from '@iota/iota-sdk/client'; import { IOTA_TYPE_ARG } from '@iota/iota-sdk/utils'; -import type { GasSummaryType, RenderExplorerLink, RenderValidatorLogo } from '../../../types'; +import type { GasSummaryType, RenderExplorerLink } from '../../../types'; import { useFormatCoin } from '../../../hooks'; -import { Divider, KeyValueInfo, Panel } from '@iota/apps-ui-kit'; -import { GasSummary, getUnstakeDetailsFromEvent } from '../../..'; +import { Divider, KeyValueInfo, Panel, CardType } from '@iota/apps-ui-kit'; +import { GasSummary, getUnstakeDetailsFromEvent, Validator } from '../../..'; interface UnstakeTransactionInfoProps { activeAddress: string | null; event: IotaEvent; - renderValidatorLogo: RenderValidatorLogo; renderExplorerLink: RenderExplorerLink; gasSummary?: GasSummaryType; } @@ -22,7 +21,6 @@ export function UnstakeTransactionInfo({ activeAddress, event, gasSummary, - renderValidatorLogo: ValidatorLogo, renderExplorerLink, }: UnstakeTransactionInfoProps) { const { principalAmount, rewardAmount, totalAmount, validatorAddress } = @@ -33,7 +31,7 @@ export function UnstakeTransactionInfo({ return (
- {validatorAddress && } + {validatorAddress && } {totalAmount !== 0n && ( )} diff --git a/apps/core/src/interfaces/index.ts b/apps/core/src/interfaces/index.ts index 4781308fa2b..226be390797 100644 --- a/apps/core/src/interfaces/index.ts +++ b/apps/core/src/interfaces/index.ts @@ -1,7 +1,6 @@ // Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -export * from './validatorLogo.interfaces'; export * from './balanceChange.interfaces'; export * from './transactions.interfaces'; export * from './stakeEvent.interfaces'; diff --git a/apps/core/src/interfaces/validatorLogo.interfaces.ts b/apps/core/src/interfaces/validatorLogo.interfaces.ts deleted file mode 100644 index 26b2d558ff2..00000000000 --- a/apps/core/src/interfaces/validatorLogo.interfaces.ts +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -export interface ValidatorLogoProps { - address: string; - isSelected: boolean; - showActiveStatus?: boolean; - activeEpoch?: string; -} diff --git a/apps/core/src/types/renderComponent.ts b/apps/core/src/types/renderComponent.ts index 3059aa3f24d..b28b83ce439 100644 --- a/apps/core/src/types/renderComponent.ts +++ b/apps/core/src/types/renderComponent.ts @@ -3,8 +3,6 @@ import type { PropsWithChildren, JSX } from 'react'; import type { ExplorerLinkConfig } from '../utils/getExplorerLink'; -import type { ValidatorLogoProps } from '../interfaces'; export type RenderExplorerLinkProps = PropsWithChildren; export type RenderExplorerLink = (props: RenderExplorerLinkProps) => JSX.Element; -export type RenderValidatorLogo = (props: ValidatorLogoProps) => JSX.Element; diff --git a/apps/wallet-dashboard/components/dialogs/TransactionDialog.tsx b/apps/wallet-dashboard/components/dialogs/TransactionDialog.tsx index 1bf34569416..71418f1b673 100644 --- a/apps/wallet-dashboard/components/dialogs/TransactionDialog.tsx +++ b/apps/wallet-dashboard/components/dialogs/TransactionDialog.tsx @@ -11,7 +11,6 @@ import { ViewTxnOnExplorerButton, } from '@iota/core'; import { useCurrentAccount } from '@iota/dapp-kit'; -import { Validator } from './staking/views/Validator'; interface SharedProps { txDigest?: string | null; @@ -43,7 +42,6 @@ export function TransactionDialogView({ activeAddress={activeAddress} summary={summary} renderExplorerLink={ExplorerLink} - renderValidatorLogo={Validator} /> ) : (
diff --git a/apps/wallet-dashboard/components/dialogs/staking/views/EnterAmountDialogLayout.tsx b/apps/wallet-dashboard/components/dialogs/staking/views/EnterAmountDialogLayout.tsx index c9b7a1555b3..dc59e18ac07 100644 --- a/apps/wallet-dashboard/components/dialogs/staking/views/EnterAmountDialogLayout.tsx +++ b/apps/wallet-dashboard/components/dialogs/staking/views/EnterAmountDialogLayout.tsx @@ -1,7 +1,7 @@ // Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useFormatCoin, useStakeTxnInfo } from '@iota/core'; +import { useFormatCoin, useStakeTxnInfo, Validator } from '@iota/core'; import { IOTA_TYPE_ARG } from '@iota/iota-sdk/utils'; import { Button, @@ -19,8 +19,6 @@ import { import { Field, type FieldProps, useFormikContext } from 'formik'; import { Exclamation, Loader } from '@iota/apps-ui-icons'; import { useIotaClientQuery } from '@iota/dapp-kit'; - -import { Validator } from './Validator'; import { StakedInfo } from './StakedInfo'; import { DialogLayout, DialogLayoutBody, DialogLayoutFooter } from '../../layout'; @@ -72,7 +70,7 @@ export function EnterAmountDialogLayout({
- +
onSelect(validator)} isSelected={selectedValidator === validator} /> ))} diff --git a/apps/wallet-dashboard/components/dialogs/transaction/TransactionDetailsLayout.tsx b/apps/wallet-dashboard/components/dialogs/transaction/TransactionDetailsLayout.tsx index 0bcc27565d8..8b7d9cfa6a2 100644 --- a/apps/wallet-dashboard/components/dialogs/transaction/TransactionDetailsLayout.tsx +++ b/apps/wallet-dashboard/components/dialogs/transaction/TransactionDetailsLayout.tsx @@ -13,7 +13,6 @@ import { } from '@iota/core'; import { useCurrentAccount, useIotaClientContext } from '@iota/dapp-kit'; import { DialogLayoutBody, DialogLayoutFooter } from '../layout'; -import { Validator } from '../staking/views/Validator'; import { Network } from '@iota/iota-sdk/client'; interface TransactionDialogDetailsProps { @@ -42,7 +41,6 @@ export function TransactionDetailsLayout({ transaction, onClose }: TransactionDi activeAddress={address} summary={summary} renderExplorerLink={ExplorerLink} - renderValidatorLogo={Validator} /> diff --git a/apps/wallet-dashboard/components/dialogs/unstake/views/UnstakeTimelockedObjectsView.tsx b/apps/wallet-dashboard/components/dialogs/unstake/views/UnstakeTimelockedObjectsView.tsx index 1ccb65e2fd1..d023d8528b2 100644 --- a/apps/wallet-dashboard/components/dialogs/unstake/views/UnstakeTimelockedObjectsView.tsx +++ b/apps/wallet-dashboard/components/dialogs/unstake/views/UnstakeTimelockedObjectsView.tsx @@ -3,7 +3,7 @@ import { StakeRewardsPanel, ValidatorStakingData } from '@/components'; import { DialogLayout, DialogLayoutBody, DialogLayoutFooter } from '../../layout'; -import { Validator } from '../../staking/views/Validator'; +import { Validator } from '@iota/core'; import { useNewUnstakeTimelockedTransaction } from '@/hooks'; import { Collapsible, diff --git a/apps/wallet-dashboard/components/dialogs/unstake/views/UnstakeView.tsx b/apps/wallet-dashboard/components/dialogs/unstake/views/UnstakeView.tsx index a547d4b3b3a..41e5d3b11f4 100644 --- a/apps/wallet-dashboard/components/dialogs/unstake/views/UnstakeView.tsx +++ b/apps/wallet-dashboard/components/dialogs/unstake/views/UnstakeView.tsx @@ -17,13 +17,14 @@ import { GAS_SYMBOL, useFormatCoin, useGetStakingValidatorDetails, + Validator, } from '@iota/core'; import { IOTA_TYPE_ARG } from '@iota/iota-sdk/utils'; import { useCurrentAccount, useSignAndExecuteTransaction } from '@iota/dapp-kit'; import { Warning } from '@iota/apps-ui-icons'; import { StakeRewardsPanel, ValidatorStakingData } from '@/components'; import { DialogLayout, DialogLayoutFooter, DialogLayoutBody } from '../../layout'; -import { Validator } from '../../staking/views/Validator'; + import { useNewUnstakeTransaction } from '@/hooks'; import { IotaSignAndExecuteTransactionOutput } from '@iota/wallet-standard'; import toast from 'react-hot-toast'; diff --git a/apps/wallet/src/ui/app/components/receipt-card/index.tsx b/apps/wallet/src/ui/app/components/receipt-card/index.tsx index 45119b9470e..2c8e6a82c51 100644 --- a/apps/wallet/src/ui/app/components/receipt-card/index.tsx +++ b/apps/wallet/src/ui/app/components/receipt-card/index.tsx @@ -11,8 +11,6 @@ import { } from '@iota/core'; import { type IotaTransactionBlockResponse } from '@iota/iota-sdk/client'; -import { CardType } from '@iota/apps-ui-kit'; -import { ValidatorLogo } from '../../staking/validators/ValidatorLogo'; import { ExplorerLinkHelper } from '../ExplorerLinkHelper'; import { ExplorerLink } from '../explorer-link'; @@ -40,14 +38,6 @@ export function ReceiptCard({ txn, activeAddress }: ReceiptCardProps) { summary={summary} activeAddress={activeAddress} renderExplorerLink={ExplorerLinkHelper} - renderValidatorLogo={({ address, showActiveStatus, activeEpoch, isSelected }) => ( - - )} />
diff --git a/apps/wallet/src/ui/app/staking/delegation-detail/DelegationDetailCard.tsx b/apps/wallet/src/ui/app/staking/delegation-detail/DelegationDetailCard.tsx index 8d007ffab9c..4ed1e6df5fa 100644 --- a/apps/wallet/src/ui/app/staking/delegation-detail/DelegationDetailCard.tsx +++ b/apps/wallet/src/ui/app/staking/delegation-detail/DelegationDetailCard.tsx @@ -14,6 +14,7 @@ import { useFormatCoin, formatPercentageDisplay, MIN_NUMBER_IOTA_TO_STAKE, + Validator, } from '@iota/core'; import { useIotaClientQuery } from '@iota/dapp-kit'; import { Network, type StakeObject } from '@iota/iota-sdk/client'; @@ -34,7 +35,6 @@ import { LoadingIndicator, } from '@iota/apps-ui-kit'; import { useNavigate } from 'react-router-dom'; -import { ValidatorLogo } from '../validators/ValidatorLogo'; import { Warning } from '@iota/apps-ui-icons'; import toast from 'react-hot-toast'; @@ -143,7 +143,7 @@ export function DelegationDetailCard({ validatorAddress, stakedId }: DelegationD return (
- + {hasInactiveValidatorDelegation ? ( ( <>
- + - { selectValidator(validator); }} diff --git a/apps/wallet/src/ui/app/staking/validators/ValidatorLogo.tsx b/apps/wallet/src/ui/app/staking/validators/ValidatorLogo.tsx deleted file mode 100644 index ce7d889291e..00000000000 --- a/apps/wallet/src/ui/app/staking/validators/ValidatorLogo.tsx +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// Modifications Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 -import { - Badge, - BadgeType, - Card, - CardAction, - CardActionType, - CardBody, - CardImage, - type CardType, -} from '@iota/apps-ui-kit'; -import { useIotaClientQuery } from '@iota/dapp-kit'; -import { formatAddress } from '@iota/iota-sdk/utils'; -import { useMemo } from 'react'; -import { formatPercentageDisplay, useGetValidatorsApy, ImageIcon, ImageIconSize } from '@iota/core'; - -interface ValidatorLogoProps { - validatorAddress: string; - type?: CardType; - showApy?: boolean; - showActiveStatus?: boolean; - activeEpoch?: string; - onClick?(): void; -} - -export function ValidatorLogo({ - validatorAddress, - type, - showApy, - showActiveStatus = false, - activeEpoch, - onClick, -}: ValidatorLogoProps) { - const { data: system, isPending } = useIotaClientQuery('getLatestIotaSystemState'); - const { data: rollingAverageApys } = useGetValidatorsApy(); - const { apy, isApyApproxZero } = rollingAverageApys?.[validatorAddress] ?? { - apy: null, - }; - - const validatorMeta = useMemo(() => { - if (!system) return null; - - return ( - system.activeValidators.find( - (validator) => validator.iotaAddress === validatorAddress, - ) || null - ); - }, [validatorAddress, system]); - - const stakingPoolActivationEpoch = Number(validatorMeta?.stakingPoolActivationEpoch || 0); - const currentEpoch = Number(system?.epoch || 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); - - if (isPending) { - return
...
; - } - // for inactive validators, show the epoch number - const fallBackText = activeEpoch - ? `Staked ${Number(system?.epoch) - Number(activeEpoch)} epochs ago` - : '--'; - const validatorName = validatorMeta?.name || fallBackText; - - const subtitle = validatorAddress ? ( - showActiveStatus ? ( -
- {formatAddress(validatorAddress)} - {newValidator && } - {isAtRisk && } -
- ) : ( - formatAddress(validatorAddress) - ) - ) : ( - '--' - ); - return ( - <> - - - - - - {showApy && ( - - )} - - - ); -}