diff --git a/apps/explorer/src/components/AddressesCardGraph.tsx b/apps/explorer/src/components/AddressesCardGraph.tsx index a008e55e007..4f6b0d6cc1c 100644 --- a/apps/explorer/src/components/AddressesCardGraph.tsx +++ b/apps/explorer/src/components/AddressesCardGraph.tsx @@ -55,7 +55,6 @@ export function AddressesCardGraph(): JSX.Element { ? addressMetrics.cumulativeAddresses.toString() : '--' } - showSupportingLabel={false} /> @@ -68,7 +67,6 @@ export function AddressesCardGraph(): JSX.Element { ? addressMetrics.cumulativeActiveAddresses.toString() : '--' } - showSupportingLabel={false} /> @@ -80,7 +78,6 @@ export function AddressesCardGraph(): JSX.Element { ? addressMetrics.dailyActiveAddresses.toString() : '--' } - showSupportingLabel={false} />
{isPending ? ( diff --git a/apps/explorer/src/components/TransactionsCardGraph.tsx b/apps/explorer/src/components/TransactionsCardGraph.tsx index 72f3f647291..1273c6f8c0e 100644 --- a/apps/explorer/src/components/TransactionsCardGraph.tsx +++ b/apps/explorer/src/components/TransactionsCardGraph.tsx @@ -85,7 +85,6 @@ export function TransactionsCardGraph() { size={LabelTextSize.Large} label="Total" text={totalTransactions ? formatBalance(totalTransactions, 0) : '--'} - showSupportingLabel={false} />
@@ -98,7 +97,6 @@ export function TransactionsCardGraph() { ? lastEpochTotalTransactions.toString() : '--' } - showSupportingLabel={false} /> diff --git a/apps/explorer/src/components/home-metrics/CurrentEpoch.tsx b/apps/explorer/src/components/home-metrics/CurrentEpoch.tsx index dc97efc7b0d..6fd692336ef 100644 --- a/apps/explorer/src/components/home-metrics/CurrentEpoch.tsx +++ b/apps/explorer/src/components/home-metrics/CurrentEpoch.tsx @@ -52,12 +52,7 @@ export function CurrentEpoch(): JSX.Element {
- +
diff --git a/apps/explorer/src/components/home-metrics/OnTheNetwork.tsx b/apps/explorer/src/components/home-metrics/OnTheNetwork.tsx index 2b7ee68e7e5..c2cf1bb57b6 100644 --- a/apps/explorer/src/components/home-metrics/OnTheNetwork.tsx +++ b/apps/explorer/src/components/home-metrics/OnTheNetwork.tsx @@ -36,7 +36,6 @@ export function OnTheNetwork(): JSX.Element { ? Math.floor(networkMetrics.currentTps).toString() : '-' } - showSupportingLabel={false} />
@@ -49,7 +48,6 @@ export function OnTheNetwork(): JSX.Element { ? Math.floor(networkMetrics?.tps30Days).toString() : '-' } - showSupportingLabel={false} /> @@ -62,7 +60,6 @@ export function OnTheNetwork(): JSX.Element { size={LabelTextSize.Large} label="Total Packages" text={networkMetrics?.totalPackages ?? '-'} - showSupportingLabel={false} />
@@ -70,7 +67,6 @@ export function OnTheNetwork(): JSX.Element { size={LabelTextSize.Large} label="Objects" text={networkMetrics?.totalObjects ?? '-'} - showSupportingLabel={false} />
@@ -81,8 +77,7 @@ export function OnTheNetwork(): JSX.Element { size={LabelTextSize.Large} label="Reference Gas Price" text={gasPriceFormatted ?? '-'} - showSupportingLabel={gasPriceFormatted !== null} - supportingLabel="IOTA" + supportingLabel={gasPriceFormatted !== null ? 'IOTA' : undefined} />
@@ -90,8 +85,7 @@ export function OnTheNetwork(): JSX.Element { size={LabelTextSize.Large} label="Total Supply" text={totalSupplyFormatted ?? '-'} - showSupportingLabel={totalSupplyFormatted !== null} - supportingLabel="IOTA" + supportingLabel={totalSupplyFormatted !== null ? 'IOTA' : undefined} />
diff --git a/apps/explorer/src/components/owned-objects/ListView.tsx b/apps/explorer/src/components/owned-objects/ListView.tsx index 86032e74498..18af17be072 100644 --- a/apps/explorer/src/components/owned-objects/ListView.tsx +++ b/apps/explorer/src/components/owned-objects/ListView.tsx @@ -69,7 +69,7 @@ function ListViewItemContainer({ obj }: { obj: IotaObjectResponse }): JSX.Elemen subtitle={type} src={displayMeta?.image_url || ''} video={video} - variant="xs" + variant="xxs" />
diff --git a/apps/explorer/src/components/owned-objects/SmallThumbnailsView.tsx b/apps/explorer/src/components/owned-objects/SmallThumbnailsView.tsx index 9a3c97b3e2d..a75da63960c 100644 --- a/apps/explorer/src/components/owned-objects/SmallThumbnailsView.tsx +++ b/apps/explorer/src/components/owned-objects/SmallThumbnailsView.tsx @@ -2,12 +2,11 @@ // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +import { Tooltip, TooltipPosition } from '@iota/apps-ui-kit'; import { type IotaObjectResponse } from '@iota/iota-sdk/client'; import { formatAddress } from '@iota/iota-sdk/utils'; -import { Placeholder } from '@iota/ui'; +import { Info, Loader } from '@iota/ui-icons'; import { type ReactNode } from 'react'; - -import { OwnedObjectsText } from '~/components'; import { ObjectLink, ObjectVideoImage } from '~/components/ui'; import { useResolveVideo } from '~/hooks/useResolveVideo'; import { parseObjectType, trimStdLibPrefix } from '~/lib/utils'; @@ -25,8 +24,8 @@ interface OwnObjectContainerProps { function OwnObjectContainer({ id, children }: OwnObjectContainerProps): JSX.Element { return ( -
-
+
+
@@ -38,7 +37,7 @@ function SmallThumbnailsViewLoading({ limit }: { limit: number }): JSX.Element { <> {new Array(limit).fill(0).map((_, index) => ( - + ))} @@ -54,7 +53,7 @@ function SmallThumbnail({ obj }: { obj: IotaObjectResponse }): JSX.Element { const id = obj.data?.objectId; return ( -
+
- -
- - {name} - - - {formatAddress(id!)} - +
+ {name} +
+ + {formatAddress(id!)} + + + + +
); @@ -83,7 +84,7 @@ export function SmallThumbnailsView({ limit, }: SmallThumbnailsViewProps): JSX.Element { return ( -
+
{loading && } {data?.map((obj, index) => { const id = obj.data?.objectId; diff --git a/apps/explorer/src/components/top-validators-card/TopValidatorsCard.tsx b/apps/explorer/src/components/top-validators-card/TopValidatorsCard.tsx index dbc324cc8d6..ee08d4967db 100644 --- a/apps/explorer/src/components/top-validators-card/TopValidatorsCard.tsx +++ b/apps/explorer/src/components/top-validators-card/TopValidatorsCard.tsx @@ -4,119 +4,28 @@ import { useIotaClientQuery } from '@iota/dapp-kit'; import { ArrowRight12 } from '@iota/icons'; -import { type IotaValidatorSummary } from '@iota/iota-sdk/client'; import { Text } from '@iota/ui'; -import { type ReactNode, useMemo } from 'react'; +import { useMemo } from 'react'; -import { HighlightedTableCol } from '~/components'; -import { - AddressLink, - Banner, - ImageIcon, - Link, - PlaceholderTable, - TableCard, - ValidatorLink, -} from '~/components/ui'; -import { ampli } from '~/lib/utils'; -import { StakeColumn } from './StakeColumn'; +import { Banner, Link, PlaceholderTable, TableCard } from '~/components/ui'; +import { generateValidatorsTableData, type ValidatorTableColumn } from '~/lib/ui'; const NUMBER_OF_VALIDATORS = 10; -export function processValidators(set: IotaValidatorSummary[]) { - return set.map((av) => ({ - name: av.name, - address: av.iotaAddress, - stake: av.stakingPoolIotaBalance, - logo: av.imageUrl, - })); -} -interface ValidatorData { - name: ReactNode; - stake: ReactNode; - delegation: ReactNode; - address: ReactNode; -} - -interface TableColumn { - header: string; - accessorKey: keyof ValidatorData; -} - -interface ValidatorsTableData { - data: ValidatorData[]; - columns: TableColumn[]; -} - -function validatorsTable( - validatorsData: IotaValidatorSummary[], - limit?: number, - showIcon?: boolean, -): ValidatorsTableData { - const validators = processValidators(validatorsData).sort(() => (Math.random() > 0.5 ? -1 : 1)); - - const validatorsItems = limit ? validators.splice(0, limit) : validators; - - return { - data: validatorsItems.map(({ name, stake, address, logo }) => ({ - name: ( - -
- {showIcon && ( - - )} - - ampli.clickedValidatorRow({ - sourceFlow: 'Top validators - validator name', - validatorAddress: address, - validatorName: name, - }) - } - /> -
-
- ), - stake: , - delegation: ( - - {stake.toString()} - - ), - address: ( - - - ampli.clickedValidatorRow({ - sourceFlow: 'Top validators - validator address', - validatorAddress: address, - validatorName: name, - }) - } - /> - - ), - })), - columns: [ - { - header: 'Name', - accessorKey: 'name', - }, - { - header: 'Address', - accessorKey: 'address', - }, - { - header: 'Stake', - accessorKey: 'stake', - }, - ], - }; -} +const VALIDATOR_COLUMNS: ValidatorTableColumn[] = [ + { + header: 'Name', + accessorKey: 'name', + }, + { + header: 'Address', + accessorKey: 'address', + }, + { + header: 'Stake', + accessorKey: 'stake', + }, +]; type TopValidatorsCardProps = { limit?: number; @@ -127,7 +36,18 @@ export function TopValidatorsCard({ limit, showIcon }: TopValidatorsCardProps): const { data, isPending, isSuccess, isError } = useIotaClientQuery('getLatestIotaSystemState'); const tableData = useMemo( - () => (data ? validatorsTable(data.activeValidators, limit, showIcon) : null), + () => + data + ? generateValidatorsTableData({ + validators: [...data.activeValidators].sort(() => 0.5 - Math.random()), + atRiskValidators: [], + validatorEvents: [], + rollingAverageApys: null, + limit, + showValidatorIcon: showIcon, + columns: VALIDATOR_COLUMNS, + }) + : null, [data, limit, showIcon], ); diff --git a/apps/explorer/src/components/ui/ImageIcon.tsx b/apps/explorer/src/components/ui/ImageIcon.tsx index 6ad06e132e1..5b89cc52662 100644 --- a/apps/explorer/src/components/ui/ImageIcon.tsx +++ b/apps/explorer/src/components/ui/ImageIcon.tsx @@ -9,7 +9,7 @@ const imageStyle = cva(['text-white capitalize overflow-hidden bg-gray-40'], { variants: { size: { sm: 'w-6 h-6 font-medium text-subtitleSmallExtra', - md: 'w-7.5 h-7.5 font-medium text-body', + md: 'w-8 h-8 text-label-lg', lg: 'md:w-10 md:h-10 w-8 h-8 font-medium text-heading4 md:text-iconTextLarge', xl: 'md:w-31.5 md:h-31.5 w-16 h-16 font-medium text-heading4 md:text-iconTextLarge', }, @@ -38,7 +38,7 @@ interface FallBackAvatarProps { function FallBackAvatar({ fallback }: FallBackAvatarProps): JSX.Element { return ( -
+
{fallback?.slice(0, 2)}
); diff --git a/apps/explorer/src/components/ui/ObjectVideoImage.tsx b/apps/explorer/src/components/ui/ObjectVideoImage.tsx index 08253b387f9..15dddedfebe 100644 --- a/apps/explorer/src/components/ui/ObjectVideoImage.tsx +++ b/apps/explorer/src/components/ui/ObjectVideoImage.tsx @@ -11,7 +11,8 @@ import { Image, ObjectModal, type ImageProps } from '~/components/ui'; const imageStyles = cva(['z-0 flex-shrink-0 relative'], { variants: { variant: { - xs: 'h-8 w-8', + xxs: 'h-8 w-8', + xs: 'h-12 w-12', small: 'h-16 w-16', medium: 'md:h-31.5 md:w-31.5 h-16 w-16', large: 'h-50 w-50', diff --git a/apps/explorer/src/components/ui/RingChart.tsx b/apps/explorer/src/components/ui/RingChart.tsx index 0b3e723d545..7f320e307b6 100644 --- a/apps/explorer/src/components/ui/RingChart.tsx +++ b/apps/explorer/src/components/ui/RingChart.tsx @@ -2,7 +2,6 @@ // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { Heading } from '@iota/ui'; import clsx from 'clsx'; import { Fragment } from 'react'; @@ -20,7 +19,6 @@ type RingChartData = { interface RingChartLegendProps { data: RingChartData; - title: string; } function getColorFromGradient({ deg, values }: Gradient): string { @@ -37,51 +35,48 @@ function getColorFromGradient({ deg, values }: Gradient): string { return `linear-gradient(${gradientResult.join(',')})`; } -export function RingChartLegend({ data, title }: RingChartLegendProps): JSX.Element { +export function RingChartLegend({ data }: RingChartLegendProps): JSX.Element { return ( -
- - {title} - - -
- {data.map(({ color, gradient, label, value }) => { - const colorDisplay = gradient ? getColorFromGradient(gradient) : color; - - return ( + <> + {data.map(({ color, gradient, label, value }) => { + const colorDisplay = gradient ? getColorFromGradient(gradient) : color; + + return ( +
-
-
- {value} {label} -
+ style={{ background: colorDisplay }} + className="h-1.5 w-1.5 rounded-full" + /> +
+ {value} {label}
- ); - })} -
-
+
+ ); + })} + ); } -export interface RingChartProps { - data: RingChartData; +interface RingChartProperties { + cx?: number; + cy?: number; + radius?: number; + width?: number; } -export function RingChart({ data }: RingChartProps): JSX.Element { - const radius = 20; - const cx = 25; - const cy = 25; +export interface RingChartProps extends RingChartProperties { + data: RingChartData; +} +export function RingChart({ + data, + cx = 25, + cy = 25, + radius = 20, + width = 5, +}: RingChartProps): JSX.Element { const dashArray = 2 * Math.PI * radius; const startAngle = -90; const total = data.reduce((acc, { value }) => acc + value, 0); @@ -91,8 +86,9 @@ export function RingChart({ data }: RingChartProps): JSX.Element { const gradientId = `gradient-${idx}`; const ratio = (100 / total) * value; const angle = (filled * 360) / 100 + startAngle; - const offset = dashArray - (dashArray * ratio) / 100; + const offset = dashArray - (dashArray * (ratio * 0.98)) / 100; filled += ratio; + return ( {gradient && ( @@ -110,9 +106,10 @@ export function RingChart({ data }: RingChartProps): JSX.Element { r={radius} fill="transparent" stroke={gradient ? `url(#${gradientId})` : color} - strokeWidth={5} + strokeWidth={width} strokeDasharray={dashArray} strokeDashoffset={offset} + strokeLinecap="round" transform={`rotate(${angle} ${cx} ${cy})`} /> @@ -121,14 +118,12 @@ export function RingChart({ data }: RingChartProps): JSX.Element { return (
- + {segments}
- - {total} - + {total}
diff --git a/apps/explorer/src/components/ui/TableCard.tsx b/apps/explorer/src/components/ui/TableCard.tsx index 5768cc5f779..98572fbcd6f 100644 --- a/apps/explorer/src/components/ui/TableCard.tsx +++ b/apps/explorer/src/components/ui/TableCard.tsx @@ -17,19 +17,21 @@ import { type ColumnDef, getCoreRowModel, getSortedRowModel, + type RowData, type SortingState, useReactTable, } from '@tanstack/react-table'; import clsx from 'clsx'; -import { useMemo, useState } from 'react'; +import { useState } from 'react'; import { useNavigateWithQuery } from './LinkWithQuery'; -export interface TableCardProps { +export interface TableCardProps { refetching?: boolean; data: DataType[]; columns: ColumnDef[]; sortTable?: boolean; defaultSorting?: SortingState; + areHeadersCentered?: boolean; paginationOptions?: TablePaginationOptions; totalLabel?: string; viewAll?: string; @@ -41,6 +43,7 @@ export function TableCard({ columns, sortTable, defaultSorting, + areHeadersCentered, paginationOptions, totalLabel, viewAll, @@ -48,22 +51,9 @@ export function TableCard({ const navigate = useNavigateWithQuery(); const [sorting, setSorting] = useState(defaultSorting || []); - // Use Columns to create a table - const processedcol = useMemo[]>( - () => - columns.map((column) => ({ - ...column, - // cell renderer for each column from react-table - // cell should be in the column definition - //TODO: move cell to column definition - ...(!sortTable && { cell: ({ getValue }) => getValue() }), - })), - [columns, sortTable], - ); - const table = useReactTable({ data, - columns: processedcol, + columns, getCoreRowModel: getCoreRowModel(), getSortedRowModel: getSortedRowModel(), onSortingChange: setSorting, @@ -106,6 +96,7 @@ export function TableCard({ ? column.getToggleSortingHandler() : undefined } + isContentCentered={areHeadersCentered} /> ))} diff --git a/apps/explorer/src/components/ui/image/Image.tsx b/apps/explorer/src/components/ui/image/Image.tsx index b61c47f9b91..17898945c9a 100644 --- a/apps/explorer/src/components/ui/image/Image.tsx +++ b/apps/explorer/src/components/ui/image/Image.tsx @@ -2,8 +2,8 @@ // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { EyeClose16, NftTypeImage24 } from '@iota/icons'; import { LoadingIndicator } from '@iota/ui'; +import { PlaceholderReplace, VisibilityOff } from '@iota/ui-icons'; import { cva, cx, type VariantProps } from 'class-variance-authority'; import clsx from 'clsx'; import { useAnimate } from 'framer-motion'; @@ -92,7 +92,7 @@ function BaseImage({ ref={scope} className={cx( imageStyles({ size, rounded, aspect }), - 'relative flex items-center justify-center bg-gray-40 text-gray-65', + 'relative flex items-center justify-center bg-neutral-96 text-neutral-40 dark:bg-neutral-10 dark:text-neutral-60', animateFadeIn && 'opacity-0', )} > @@ -102,17 +102,17 @@ function BaseImage({ isBlurred && (
setIsBlurred(!isBlurred)} > - +
) ) : status === 'failed' ? ( - + ) : null} {status === 'loaded' && ( @@ -61,7 +60,6 @@ export function ValidatorStats({ label="Total IOTA Staked" text={formattedTotalStakeAmount} supportingLabel={totalStakeSymbol} - showSupportingLabel tooltipText="The total amount of IOTA staked on the network by validators and delegators to secure the network and earn rewards." tooltipPosition={TooltipPosition.Right} /> @@ -71,7 +69,6 @@ export function ValidatorStats({ size={LabelTextSize.Medium} label="Commission" text={`${commission}%`} - showSupportingLabel={false} tooltipText="The charge imposed by the validator for their staking services." tooltipPosition={TooltipPosition.Right} /> @@ -79,7 +76,6 @@ export function ValidatorStats({ size={LabelTextSize.Medium} label="Delegators" text={numberOfDelegators || '--'} - showSupportingLabel={false} tooltipText={ !numberOfDelegators ? 'Coming soon' @@ -97,7 +93,6 @@ export function ValidatorStats({ size={LabelTextSize.Medium} label="Last Epoch Rewards" text={typeof epochRewards === 'number' ? formattedEpochRewards : '0'} - showSupportingLabel supportingLabel={epochRewardsSymbol} tooltipText={ epochRewards === null @@ -111,7 +106,6 @@ export function ValidatorStats({ label="Reward Pool" text={formattedRewardsPoolBalance} supportingLabel={rewardsPoolBalanceSymbol} - showSupportingLabel tooltipText={ Number(rewardsPoolBalance) <= 0 ? 'Coming soon' @@ -129,7 +123,6 @@ export function ValidatorStats({ size={LabelTextSize.Medium} label="Checkpoint Participation" text={networkStakingParticipation || '--'} - showSupportingLabel={false} tooltipText={ !networkStakingParticipation ? 'Coming soon' @@ -141,7 +134,6 @@ export function ValidatorStats({ size={LabelTextSize.Medium} label="Voted Last Round" text={votedLastRound || '--'} - showSupportingLabel={false} tooltipText={ !votedLastRound ? 'Coming soon' @@ -155,7 +147,6 @@ export function ValidatorStats({ size={LabelTextSize.Medium} label="Tallying Score" text={tallyingScore ?? '--'} - showSupportingLabel={false} tooltipText={ !tallyingScore ? 'Coming soon' @@ -167,7 +158,6 @@ export function ValidatorStats({ size={LabelTextSize.Medium} label="Last Narwhal round" text={lastNarwhalRound || '--'} - showSupportingLabel={false} tooltipText={ !lastNarwhalRound ? 'Coming soon' @@ -181,7 +171,6 @@ export function ValidatorStats({ size={LabelTextSize.Medium} label="Proposed next epoch gas price" text={nextEpochGasPriceAmount} - showSupportingLabel supportingLabel="nano" tooltipText="The gas price estimate provided by this validator for the upcoming epoch." tooltipPosition={TooltipPosition.Right} diff --git a/apps/explorer/src/lib/ui/utils/generateValidatorsTableData.tsx b/apps/explorer/src/lib/ui/utils/generateValidatorsTableData.tsx new file mode 100644 index 00000000000..3eabb06a9af --- /dev/null +++ b/apps/explorer/src/lib/ui/utils/generateValidatorsTableData.tsx @@ -0,0 +1,302 @@ +// Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +import React from 'react'; +import { + BadgeType, + type TableCellProps, + TableCellType, + TableCellTextColor, +} from '@iota/apps-ui-kit'; +import type { ColumnDef } from '@tanstack/react-table'; +import { type ApyByValidator, formatPercentageDisplay } from '@iota/core'; + +import { ampli, getValidatorMoveEvent, VALIDATOR_LOW_STAKE_GRACE_PERIOD } from '~/lib'; +import { Link, StakeColumn, AddressLink, ImageIcon } from '~/components'; +import type { IotaEvent, IotaValidatorSummary } from '@iota/iota-sdk/dist/cjs/client'; + +interface ValidatorTableRow { + name: TableCellProps; + stake: TableCellProps; + apy: TableCellProps; + nextEpochGasPrice: TableCellProps; + commission: TableCellProps; + address: TableCellProps; + lastReward: TableCellProps; + votingPower: TableCellProps; + atRisk: TableCellProps; +} + +interface GenerateValidatorsTableDataArgs { + validators: IotaValidatorSummary[]; + atRiskValidators: [string, string][]; + validatorEvents: IotaEvent[]; + rollingAverageApys: ApyByValidator | null; + limit?: number; + showValidatorIcon?: boolean; + columns?: ColumnDef[]; +} + +const ALL_VALIDATOR_COLUMNS = [ + { + header: '#', + accessorKey: 'number', + }, + { + header: 'Name', + accessorKey: 'name', + }, + { + header: 'Stake', + accessorKey: 'stake', + }, + { + header: 'Proposed Next Epoch Gas Price', + accessorKey: 'nextEpochGasPrice', + }, + { + header: 'Address', + accessorKey: 'address', + }, + { + header: 'APY', + accessorKey: 'apy', + }, + { + header: 'Commission', + accessorKey: 'commission', + }, + { + header: 'Last Epoch Rewards', + accessorKey: 'lastReward', + }, + { + header: 'Voting Power', + accessorKey: 'votingPower', + }, + { + header: 'Status', + accessorKey: 'atRisk', + }, +] as const; + +type AccessorKey = (typeof ALL_VALIDATOR_COLUMNS)[number]['accessorKey']; + +export interface ValidatorTableColumn { + header: string; + accessorKey: AccessorKey; +} + +const DEFAULT_COLUMNS: ValidatorTableColumn[] = [ + { + header: '#', + accessorKey: 'number', + }, + { + header: 'Name', + accessorKey: 'name', + }, + { + header: 'Stake', + accessorKey: 'stake', + }, + { + header: 'Proposed Next Epoch Gas Price', + accessorKey: 'nextEpochGasPrice', + }, + { + header: 'APY', + accessorKey: 'apy', + }, + { + header: 'Commission', + accessorKey: 'commission', + }, + { + header: 'Last Epoch Rewards', + accessorKey: 'lastReward', + }, + { + header: 'Voting Power', + accessorKey: 'votingPower', + }, + { + header: 'Status', + accessorKey: 'atRisk', + }, +]; + +function generateValidatorAtRisk(atRisk: number | null): TableCellProps { + if (atRisk === null) { + return { + type: TableCellType.Badge, + badgeType: BadgeType.PrimarySoft, + label: 'Active', + }; + } + + const atRiskText = atRisk > 1 ? `in ${atRisk} epochs` : 'next epoch'; + return { + type: TableCellType.Badge, + badgeType: BadgeType.Neutral, + label: `At Risk ${atRiskText}`, + }; +} + +function ValidatorName({ + address, + name, + imageUrl, +}: { + address: string; + name: string; + imageUrl: string; +}) { + return ( + + ampli.clickedValidatorRow({ + sourceFlow: 'Epoch details', + validatorAddress: address, + validatorName: name, + }) + } + > +
+ + {name} +
+ + ); +} + +function ValidatorAddress({ + address, + name, + limit, +}: { + address: string; + name: string; + limit?: number; +}) { + return ( +
+ + ampli.clickedValidatorRow({ + sourceFlow: 'Top validators - validator address', + validatorAddress: address, + validatorName: name, + }) + } + /> +
+ ); +} + +export function generateValidatorsTableData({ + validators, + limit, + atRiskValidators = [], + validatorEvents = [], + rollingAverageApys = null, + showValidatorIcon = true, + columns = DEFAULT_COLUMNS, +}: GenerateValidatorsTableDataArgs): { + data: ValidatorTableRow[]; + columns: ColumnDef[]; +} { + return { + data: validators.map((validator, i) => { + const validatorName = validator.name; + const totalStake = validator.stakingPoolIotaBalance; + + const event = getValidatorMoveEvent(validatorEvents, validator.iotaAddress) as { + pool_staking_reward?: string; + }; + + const atRiskValidator = atRiskValidators.find( + ([address]) => address === validator.iotaAddress, + ); + const isAtRisk = !!atRiskValidator; + const lastReward = event?.pool_staking_reward ?? null; + const { apy, isApyApproxZero } = rollingAverageApys?.[validator.iotaAddress] ?? { + apy: null, + }; + + return { + number: { + type: TableCellType.Text, + label: `${i + 1}`, + textColor: TableCellTextColor.Dark, + }, + name: showValidatorIcon + ? { + type: TableCellType.Children, + children: ( + + ), + } + : { + type: TableCellType.Text, + label: validatorName, + textColor: TableCellTextColor.Dark, + }, + stake: { + type: TableCellType.Children, + children: , + noWrap: true, + }, + nextEpochGasPrice: { + type: TableCellType.Children, + children: , + noWrap: true, + }, + apy: { + type: TableCellType.Text, + label: formatPercentageDisplay(apy, '--', isApyApproxZero), + }, + commission: { + type: TableCellType.Text, + label: `${Number(validator.commissionRate) / 100}%`, + }, + lastReward: + lastReward !== null + ? { + type: TableCellType.Children, + children: , + noWrap: true, + } + : { + type: TableCellType.Text, + label: '--', + }, + votingPower: { + type: TableCellType.Text, + label: validator.votingPower ? Number(validator.votingPower) / 100 + '%' : '--', + }, + atRisk: generateValidatorAtRisk( + isAtRisk ? VALIDATOR_LOW_STAKE_GRACE_PERIOD - Number(atRiskValidator[1]) : null, + ), + address: { + type: TableCellType.Children, + children: ( + + ), + }, + }; + }), + columns: columns, + }; +} diff --git a/apps/explorer/src/lib/ui/utils/index.ts b/apps/explorer/src/lib/ui/utils/index.ts index 9c93389b7d4..217017f0324 100644 --- a/apps/explorer/src/lib/ui/utils/index.ts +++ b/apps/explorer/src/lib/ui/utils/index.ts @@ -3,4 +3,5 @@ export * from './generateTableDataFromCheckpointsData'; export * from './generateTableDataFromEpochsData'; +export * from './generateValidatorsTableData'; export * from './objectField'; diff --git a/apps/explorer/src/pages/checkpoints/CheckpointDetail.tsx b/apps/explorer/src/pages/checkpoints/CheckpointDetail.tsx index 5d57161657f..e945afe33d1 100644 --- a/apps/explorer/src/pages/checkpoints/CheckpointDetail.tsx +++ b/apps/explorer/src/pages/checkpoints/CheckpointDetail.tsx @@ -99,13 +99,11 @@ export default function CheckpointDetail(): JSX.Element { size={LabelTextSize.Medium} label="Checkpoint Sequence No." text={data.sequenceNumber} - showSupportingLabel={false} />
) : null} @@ -156,7 +153,6 @@ export default function CheckpointDetail(): JSX.Element { size={LabelTextSize.Medium} label="Aggregated Validator Signature" text={data.validatorSignature} - showSupportingLabel={false} />
) : null} @@ -183,21 +179,18 @@ export default function CheckpointDetail(): JSX.Element { size={LabelTextSize.Medium} label="Computation Fee" text={formattedComputationCost} - showSupportingLabel supportingLabel={computationCostCoinType} />
diff --git a/apps/explorer/src/pages/epochs/EpochDetail.tsx b/apps/explorer/src/pages/epochs/EpochDetail.tsx index d5d52c81ad9..43a0c3159e8 100644 --- a/apps/explorer/src/pages/epochs/EpochDetail.tsx +++ b/apps/explorer/src/pages/epochs/EpochDetail.tsx @@ -2,9 +2,7 @@ // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { CoinFormat, useFormatCoin } from '@iota/core'; import { useIotaClientQuery } from '@iota/dapp-kit'; -import { IOTA_TYPE_ARG } from '@iota/iota-sdk/utils'; import { LoadingIndicator } from '@iota/ui'; import { useQuery } from '@tanstack/react-query'; import { useMemo, useState } from 'react'; @@ -17,35 +15,53 @@ import { } from '@iota/apps-ui-kit'; import { CheckpointsTable, PageLayout } from '~/components'; -import { Banner, Stats, type StatsProps, TableCard } from '~/components/ui'; +import { Banner, TableCard } from '~/components/ui'; import { useEnhancedRpcClient } from '~/hooks/useEnhancedRpc'; -import { getEpochStorageFundFlow, getSupplyChangeAfterEpochEnd } from '~/lib/utils'; -import { validatorsTableData } from '../validators/Validators'; -import { EpochProgress } from './stats/EpochProgress'; -import { EpochStats } from './stats/EpochStats'; +import { EpochStats, EpochStatsGrid } from './stats/EpochStats'; import { ValidatorStatus } from './stats/ValidatorStatus'; - -function IotaStats({ - amount, - showSign, - ...props -}: Omit & { - amount: bigint | number | string | undefined | null; - showSign?: boolean; -}): JSX.Element { - const [formattedAmount, symbol] = useFormatCoin( - amount, - IOTA_TYPE_ARG, - CoinFormat.ROUNDED, - showSign, - ); - - return ( - - {formattedAmount || '--'} - - ); -} +import cx from 'clsx'; +import { TokenStats } from './stats/TokenStats'; +import { EpochTopStats } from './stats/EpochTopStats'; +import { getEpochStorageFundFlow } from '~/lib/utils'; +import { + generateValidatorsTableData, + type ValidatorTableColumn, +} from '~/lib/ui/utils/generateValidatorsTableData'; + +export const VALIDATOR_COLUMNS: ValidatorTableColumn[] = [ + { + header: 'Name', + accessorKey: 'name', + }, + { + header: 'Stake', + accessorKey: 'stake', + }, + { + header: 'Proposed next Epoch gas price', + accessorKey: 'nextEpochGasPrice', + }, + { + header: 'APY', + accessorKey: 'apy', + }, + { + header: 'Commission', + accessorKey: 'commission', + }, + { + header: 'Last Epoch Reward', + accessorKey: 'lastReward', + }, + { + header: 'Voting Power', + accessorKey: 'votingPower', + }, + { + header: 'Status', + accessorKey: 'atRisk', + }, +]; enum EpochTabs { Checkpoints = 'checkpoints', @@ -74,15 +90,17 @@ export default function EpochDetail() { ); const validatorsTable = useMemo(() => { - if (!epochData?.validators) return null; + if (!epochData?.validators || epochData.validators.length === 0) return null; // todo: enrich this historical validator data when we have // at-risk / pending validators for historical epochs - return validatorsTableData( - [...epochData.validators].sort(() => 0.5 - Math.random()), - [], - [], - null, - ); + return generateValidatorsTableData({ + validators: [...epochData.validators].sort(() => 0.5 - Math.random()), + atRiskValidators: [], + validatorEvents: [], + rollingAverageApys: null, + columns: VALIDATOR_COLUMNS, + showValidatorIcon: true, + }); }, [epochData]); if (isPending) return } />; @@ -111,51 +129,60 @@ export default function EpochDetail() { -
-
- + + -
- - - - - - - - - - - - - - - - - - {isCurrentEpoch ? : null} + {!isCurrentEpoch && ( + <> + + + + + + + + + + + + + + + + + + )} + + {isCurrentEpoch && }
@@ -191,7 +218,6 @@ export default function EpochDetail() { ) : null}
diff --git a/apps/explorer/src/pages/epochs/stats/EpochProgress.tsx b/apps/explorer/src/pages/epochs/stats/EpochProgress.tsx deleted file mode 100644 index 7d58416f325..00000000000 --- a/apps/explorer/src/pages/epochs/stats/EpochProgress.tsx +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// Modifications Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -import { formatDate } from '@iota/core'; -import { Heading, Text } from '@iota/ui'; -import clsx from 'clsx'; - -import { Card, ProgressBar } from '~/components/ui'; -import { getElapsedTime, useEpochProgress } from '~/pages/epochs/utils'; - -interface EpochProgressProps { - epoch?: string; - start: number; - end?: number; - inProgress?: boolean; -} - -export function EpochProgress({ epoch, start, end, inProgress }: EpochProgressProps): JSX.Element { - const { progress, label } = useEpochProgress(); - - const elapsedTime = !inProgress && start && end ? getElapsedTime(start, end) : undefined; - - return ( - -
-
-
- - {inProgress ? `Epoch ${epoch} in progress` : `Epoch ${epoch}`} - - {elapsedTime && ( - - {elapsedTime} - - )} -
-
- - Start - - - {formatDate(start)} - -
- {!inProgress && end ? ( -
- - End - - - {formatDate(end)} - -
- ) : null} -
- {inProgress ? ( -
- - {label} - - -
- ) : null} -
-
- ); -} diff --git a/apps/explorer/src/pages/epochs/stats/EpochStats.tsx b/apps/explorer/src/pages/epochs/stats/EpochStats.tsx index 625503835c3..33c15f3a31d 100644 --- a/apps/explorer/src/pages/epochs/stats/EpochStats.tsx +++ b/apps/explorer/src/pages/epochs/stats/EpochStats.tsx @@ -2,27 +2,24 @@ // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { Heading } from '@iota/ui'; -import { type ReactNode } from 'react'; +import { Panel, Title } from '@iota/apps-ui-kit'; +import type { ComponentProps } from 'react'; -import { Card } from '~/components/ui'; - -interface EpochStatsProps { - label: string; - children: ReactNode; -} - -export function EpochStats({ label, children }: EpochStatsProps): JSX.Element { +type TitleProps = ComponentProps; +export function EpochStats({ + children, + ...titleProps +}: React.PropsWithChildren): JSX.Element { return ( - -
- {label && ( - - {label} - - )} -
{children}
+ +
+ {titleProps && } + <div className="w-full p-md--rs">{children}</div> </div> - </Card> + </Panel> ); } + +export function EpochStatsGrid({ children }: React.PropsWithChildren): React.JSX.Element { + return <div className="grid w-full grid-cols-1 gap-md--rs md:grid-cols-2">{children}</div>; +} diff --git a/apps/explorer/src/pages/epochs/stats/EpochTopStats.tsx b/apps/explorer/src/pages/epochs/stats/EpochTopStats.tsx new file mode 100644 index 00000000000..c99f5a51c39 --- /dev/null +++ b/apps/explorer/src/pages/epochs/stats/EpochTopStats.tsx @@ -0,0 +1,48 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +import { ProgressBar } from '~/components'; +import { EpochStatsGrid } from './EpochStats'; +import { LabelText, LabelTextSize } from '@iota/apps-ui-kit'; +import { formatDate } from '@iota/core'; +import { TokenStats } from './TokenStats'; +import { getSupplyChangeAfterEpochEnd } from '~/lib'; +import { useEpochProgress } from '../utils'; +import type { EndOfEpochInfo } from '@iota/iota-sdk/src/client'; + +interface EpochProgressProps { + start: number; + end?: number; + inProgress?: boolean; + endOfEpochInfo?: EndOfEpochInfo | null; +} + +export function EpochTopStats({ + start, + end, + inProgress, + endOfEpochInfo, +}: EpochProgressProps): React.JSX.Element { + const { progress, label } = useEpochProgress(); + const endTime = inProgress ? label : end ? formatDate(end) : undefined; + + return ( + <div className="flex w-full flex-col gap-md--rs"> + {inProgress ? <ProgressBar progress={progress || 0} /> : null} + + <EpochStatsGrid> + <LabelText text={formatDate(start)} label="Start" /> + {endTime ? <LabelText text={endTime} label="End" /> : null} + {endOfEpochInfo && ( + <TokenStats + label="Supply Change" + size={LabelTextSize.Large} + amount={getSupplyChangeAfterEpochEnd(endOfEpochInfo)} + showSign + /> + )} + </EpochStatsGrid> + </div> + ); +} diff --git a/apps/explorer/src/pages/epochs/stats/TokenStats.tsx b/apps/explorer/src/pages/epochs/stats/TokenStats.tsx new file mode 100644 index 00000000000..b7e0daa1061 --- /dev/null +++ b/apps/explorer/src/pages/epochs/stats/TokenStats.tsx @@ -0,0 +1,30 @@ +// Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +import { LabelText, LabelTextSize } from '@iota/apps-ui-kit'; +import { CoinFormat, useFormatCoin } from '@iota/core'; +import { IOTA_TYPE_ARG } from '@iota/iota-sdk/utils'; + +type LabelTextProps = Omit<React.ComponentProps<typeof LabelText>, 'text' | 'size'>; + +interface TokenStatsProps extends LabelTextProps { + amount: bigint | number | string | undefined | null; + showSign?: boolean; + size?: LabelTextSize; +} + +export function TokenStats({ + amount, + showSign, + size = LabelTextSize.Large, + ...props +}: TokenStatsProps): React.JSX.Element { + const [formattedAmount, symbol] = useFormatCoin( + amount, + IOTA_TYPE_ARG, + CoinFormat.ROUNDED, + showSign, + ); + + return <LabelText text={formattedAmount} supportingLabel={symbol} size={size} {...props} />; +} diff --git a/apps/explorer/src/pages/epochs/stats/ValidatorStatus.tsx b/apps/explorer/src/pages/epochs/stats/ValidatorStatus.tsx index 3131336cb3a..449029b3217 100644 --- a/apps/explorer/src/pages/epochs/stats/ValidatorStatus.tsx +++ b/apps/explorer/src/pages/epochs/stats/ValidatorStatus.tsx @@ -2,12 +2,12 @@ // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +import { DisplayStats, IOTA_PRIMITIVES_COLOR_PALETTE, Panel, Title } from '@iota/apps-ui-kit'; import { getRefGasPrice } from '@iota/core'; import { useIotaClientQuery } from '@iota/dapp-kit'; -import { Heading, Text } from '@iota/ui'; import { useMemo } from 'react'; -import { Card, RingChart, RingChartLegend } from '~/components/ui'; +import { RingChart, RingChartLegend } from '~/components/ui'; export function ValidatorStatus(): JSX.Element | null { const { data } = useIotaClientQuery('getLatestIotaSystemState'); @@ -21,6 +21,9 @@ export function ValidatorStatus(): JSX.Element | null { const nextEpoch = Number(data.epoch || 0) + 1; + const getHexColorWithOpacity = (color: string, opacity: number) => + `${color}${Math.round(opacity * 255).toString(16)}`; + const chartData = [ { value: data.activeValidators.length, @@ -28,53 +31,47 @@ export function ValidatorStatus(): JSX.Element | null { gradient: { deg: 315, values: [ - { percent: 0, color: '#4C75A6' }, - { percent: 100, color: '#589AEA' }, + { percent: 0, color: IOTA_PRIMITIVES_COLOR_PALETTE.primary[30] }, + { percent: 100, color: IOTA_PRIMITIVES_COLOR_PALETTE.primary[30] }, ], }, }, { value: Number(data.pendingActiveValidatorsSize ?? 0), label: 'New', - color: '#F2BD24', + color: getHexColorWithOpacity(IOTA_PRIMITIVES_COLOR_PALETTE.primary[30], 0.6), }, { value: data.atRiskValidators.length, label: 'At Risk', - color: '#FF794B', + color: IOTA_PRIMITIVES_COLOR_PALETTE.neutral[90], }, ]; return ( - <Card spacing="lg" bg="white" border="steel" rounded="2xl"> - <div className="flex items-center gap-5"> - <div className="min-h-[96px] min-w-[96px]"> - <RingChart data={chartData} /> - </div> - - <div className="self-start"> - <RingChartLegend data={chartData} title={`Validators in Epoch ${nextEpoch}`} /> - </div> - </div> + <Panel> + <div className="flex flex-col"> + <Title title={`Validators in Epoch ${nextEpoch}`} /> + <div className="flex flex-col items-start justify-center gap-x-xl gap-y-sm p-md--rs md:flex-row md:items-center md:justify-between md:gap-sm--rs"> + <div className="flex w-auto flex-row gap-x-md p-md md:max-w-[50%]"> + <div className="h-[92px] w-[92px]"> + <RingChart data={chartData} width={4} /> + </div> + <div className="flex flex-col items-center justify-center gap-xs lg:items-start"> + <RingChartLegend data={chartData} /> + </div> + </div> - <div className="mt-8 flex items-center justify-between rounded-lg border border-solid border-steel px-3 py-2"> - <div> - <Text variant="pSubtitle/semibold" color="steel-darker"> - Estimated Next Epoch - </Text> - <Text variant="pSubtitle/semibold" color="steel-darker"> - Reference Gas Price - </Text> - </div> - <div className="text-right"> - <Heading variant="heading4/semibold" color="steel-darker"> - {nextRefGasPrice.toString()} - </Heading> - <Text variant="pBody/medium" color="steel-darker"> - nano - </Text> + <div className="h-full w-full max-w-[250px] sm:w-1/2 md:w-auto lg:w-1/2 "> + <DisplayStats + label="Estimated Next Epoch + Reference Gas Price" + value={nextRefGasPrice.toString()} + supportingLabel="nano" + /> + </div> </div> </div> - </Card> + </Panel> ); } diff --git a/apps/explorer/src/pages/validators/Validators.tsx b/apps/explorer/src/pages/validators/Validators.tsx index a7607c1647a..b3874e85d74 100644 --- a/apps/explorer/src/pages/validators/Validators.tsx +++ b/apps/explorer/src/pages/validators/Validators.tsx @@ -2,243 +2,28 @@ // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -/* eslint-disable @typescript-eslint/no-explicit-any */ - +import React, { type JSX, useMemo } from 'react'; +import { roundFloat, useFormatCoin, useGetValidatorsApy, useGetValidatorsEvents } from '@iota/core'; import { DisplayStats, DisplayStatsSize, DisplayStatsType, TooltipPosition, } from '@iota/apps-ui-kit'; -import { - formatPercentageDisplay, - roundFloat, - useFormatCoin, - useGetValidatorsApy, - useGetValidatorsEvents, - type ApyByValidator, -} from '@iota/core'; import { useIotaClientQuery } from '@iota/dapp-kit'; -import { type IotaEvent, type IotaValidatorSummary } from '@iota/iota-sdk/client'; import { IOTA_TYPE_ARG } from '@iota/iota-sdk/utils'; -import { Text } from '@iota/ui'; -import { useMemo } from 'react'; -import { ErrorBoundary, PageLayout, StakeColumn } from '~/components'; import { + ErrorBoundary, + PageLayout, Banner, - ImageIcon, - Link, PlaceholderTable, TableCard, TableHeader, - Tooltip, -} from '~/components/ui'; -import { VALIDATOR_LOW_STAKE_GRACE_PERIOD } from '~/lib/constants'; -import { ampli, getValidatorMoveEvent } from '~/lib/utils'; - -export function validatorsTableData( - validators: IotaValidatorSummary[], - atRiskValidators: [string, string][], - validatorEvents: IotaEvent[], - rollingAverageApys: ApyByValidator | null, -) { - return { - data: [...validators] - .sort(() => 0.5 - Math.random()) - .map((validator) => { - const validatorName = validator.name; - const totalStake = validator.stakingPoolIotaBalance; - const img = validator.imageUrl; - - const event = getValidatorMoveEvent(validatorEvents, validator.iotaAddress) as { - pool_staking_reward?: string; - }; - - const atRiskValidator = atRiskValidators.find( - ([address]) => address === validator.iotaAddress, - ); - const isAtRisk = !!atRiskValidator; - const lastReward = event?.pool_staking_reward ?? null; - const { apy, isApyApproxZero } = rollingAverageApys?.[validator.iotaAddress] ?? { - apy: null, - }; - - return { - name: { - name: validatorName, - logo: validator.imageUrl, - }, - stake: totalStake, - apy: { - apy, - isApyApproxZero, - }, - nextEpochGasPrice: validator.nextEpochGasPrice, - commission: Number(validator.commissionRate) / 100, - img: img, - address: validator.iotaAddress, - lastReward: lastReward ?? null, - votingPower: Number(validator.votingPower) / 100, - atRisk: isAtRisk - ? VALIDATOR_LOW_STAKE_GRACE_PERIOD - Number(atRiskValidator[1]) - : null, - }; - }), - columns: [ - { - header: '#', - accessorKey: 'number', - cell: (props: any) => ( - <Text variant="bodySmall/medium" color="steel-dark"> - {props.table.getSortedRowModel().flatRows.indexOf(props.row) + 1} - </Text> - ), - }, - { - header: 'Name', - accessorKey: 'name', - enableSorting: true, - sortingFn: (a: any, b: any, colId: string) => - a.getValue(colId).name.localeCompare(b.getValue(colId).name, 'en', { - sensitivity: 'base', - numeric: true, - }), - cell: (props: any) => { - const { name, logo } = props.getValue(); - return ( - <Link - to={`/validator/${encodeURIComponent(props.row.original.address)}`} - onClick={() => - ampli.clickedValidatorRow({ - sourceFlow: 'Epoch details', - validatorAddress: props.row.original.address, - validatorName: name, - }) - } - > - <div className="flex items-center gap-2.5"> - <ImageIcon - src={logo} - size="sm" - label={name} - fallback={name} - circle - /> - <Text variant="bodySmall/medium" color="steel-darker"> - {name} - </Text> - </div> - </Link> - ); - }, - }, - { - header: 'Stake', - accessorKey: 'stake', - enableSorting: true, - cell: (props: any) => <StakeColumn stake={props.getValue()} />, - }, - { - header: 'Proposed Next Epoch Gas Price', - accessorKey: 'nextEpochGasPrice', - enableSorting: true, - cell: (props: any) => <StakeColumn stake={props.getValue()} inNano />, - }, - { - header: 'APY', - accessorKey: 'apy', - enableSorting: true, - sortingFn: (a: any, b: any, colId: string) => - a.getValue(colId)?.apy < b.getValue(colId)?.apy ? -1 : 1, - cell: (props: any) => { - const { apy, isApyApproxZero } = props.getValue(); - return ( - <Text variant="bodySmall/medium" color="steel-darker"> - {formatPercentageDisplay(apy, '--', isApyApproxZero)} - </Text> - ); - }, - }, - { - header: 'Commission', - accessorKey: 'commission', - enableSorting: true, - cell: (props: any) => { - const commissionRate = props.getValue(); - return ( - <Text variant="bodySmall/medium" color="steel-darker"> - {commissionRate}% - </Text> - ); - }, - }, - { - header: 'Last Epoch Rewards', - accessorKey: 'lastReward', - enableSorting: true, - cell: (props: any) => { - const lastReward = props.getValue(); - return lastReward !== null ? ( - <StakeColumn stake={Number(lastReward)} /> - ) : ( - <Text variant="bodySmall/medium" color="steel-darker"> - -- - </Text> - ); - }, - }, - { - header: 'Voting Power', - accessorKey: 'votingPower', - enableSorting: true, - cell: (props: any) => { - const votingPower = props.getValue(); - return ( - <Text variant="bodySmall/medium" color="steel-darker"> - {votingPower}% - </Text> - ); - }, - }, - { - header: 'Status', - accessorKey: 'atRisk', - cell: (props: any) => { - const atRisk = props.getValue(); - const label = 'At Risk'; - return atRisk !== null ? ( - <Tooltip - tip="Staked IOTA is below the minimum IOTA stake threshold to remain a validator." - onOpen={() => - ampli.activatedTooltip({ - tooltipLabel: label, - }) - } - > - <div className="flex cursor-pointer flex-nowrap items-center"> - <Text color="issue" variant="bodySmall/medium"> - {label} - </Text> -   - <Text uppercase variant="bodySmall/medium" color="steel-dark"> - {atRisk > 1 ? `in ${atRisk} epochs` : 'next epoch'} - </Text> - </div> - </Tooltip> - ) : ( - <Text variant="bodySmall/medium" color="steel-darker"> - Active - </Text> - ); - }, - }, - ], - }; -} +} from '~/components'; +import { generateValidatorsTableData } from '~/lib/ui/utils/generateValidatorsTableData'; function ValidatorPageResult(): JSX.Element { const { data, isPending, isSuccess, isError } = useIotaClientQuery('getLatestIotaSystemState'); - const numberOfValidators = data?.activeValidators.length || 0; const { @@ -289,12 +74,12 @@ function ValidatorPageResult(): JSX.Element { const validatorsTable = useMemo(() => { if (!data || !validatorEvents) return null; - return validatorsTableData( - data.activeValidators, - data.atRiskValidators, + return generateValidatorsTableData({ + validators: [...data.activeValidators].sort(() => 0.5 - Math.random()), + atRiskValidators: data.atRiskValidators, validatorEvents, - validatorsApy || null, - ); + rollingAverageApys: validatorsApy || null, + }); }, [data, validatorEvents, validatorsApy]); const [formattedTotalStakedAmount, totalStakedSymbol] = useFormatCoin( @@ -370,7 +155,7 @@ function ValidatorPageResult(): JSX.Element { <TableCard data={validatorsTable.data} columns={validatorsTable.columns} - sortTable + areHeadersCentered={false} /> )} </ErrorBoundary> diff --git a/apps/ui-kit/src/lib/components/atoms/label-text/LabelText.tsx b/apps/ui-kit/src/lib/components/atoms/label-text/LabelText.tsx index f5c5c245f46..5e7f8247813 100644 --- a/apps/ui-kit/src/lib/components/atoms/label-text/LabelText.tsx +++ b/apps/ui-kit/src/lib/components/atoms/label-text/LabelText.tsx @@ -12,7 +12,7 @@ interface LabelTextProps { /** * The size of the LabelText. */ - size: LabelTextSize; + size?: LabelTextSize; /** * The position of the LabelText. */ @@ -25,10 +25,6 @@ interface LabelTextProps { * The text of the LabelText. */ label: string; - /** - * Show the supporting label. - */ - showSupportingLabel: boolean; /** * The text of the LabelText. */ @@ -44,11 +40,10 @@ interface LabelTextProps { } export function LabelText({ - size, + size = LabelTextSize.Medium, isCentered, supportingLabel, label, - showSupportingLabel, text, tooltipPosition, tooltipText, @@ -66,7 +61,7 @@ export function LabelText({ > {text} </span> - {showSupportingLabel && supportingLabel && ( + {supportingLabel && ( <span className={cx( 'font-inter text-neutral-60 dark:text-neutral-40', diff --git a/apps/ui-kit/src/lib/components/molecules/display-stats/DisplayStats.tsx b/apps/ui-kit/src/lib/components/molecules/display-stats/DisplayStats.tsx index a33f350c637..53fbac6a7ad 100644 --- a/apps/ui-kit/src/lib/components/molecules/display-stats/DisplayStats.tsx +++ b/apps/ui-kit/src/lib/components/molecules/display-stats/DisplayStats.tsx @@ -101,7 +101,7 @@ export function DisplayStats({ })} > <div className="flex flex-row items-center gap-xxs"> - <span className={cx(labelTextClass)}>{label}</span> + <span className={cx(labelTextClass, 'whitespace-pre-line')}>{label}</span> {tooltipText && ( <Tooltip text={tooltipText} position={tooltipPosition}> <Info className="opacity-40" /> diff --git a/apps/ui-kit/src/lib/components/molecules/table-cell/TableCell.tsx b/apps/ui-kit/src/lib/components/molecules/table-cell/TableCell.tsx index f993416d101..19d9045c2f6 100644 --- a/apps/ui-kit/src/lib/components/molecules/table-cell/TableCell.tsx +++ b/apps/ui-kit/src/lib/components/molecules/table-cell/TableCell.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import React from 'react'; import { BadgeType, Badge, Checkbox, ButtonUnstyled } from '../../atoms'; -import { TableCellType } from './table-cell.enums'; +import { TableCellType, TableCellTextColor } from './table-cell.enums'; import { Copy } from '@iota/ui-icons'; import cx from 'classnames'; interface TableCellBaseProps { @@ -18,6 +18,14 @@ interface TableCellBaseProps { * Whether the cell content should be centered. */ isContentCentered?: boolean; + /** + * The color of the text. + */ + textColor?: TableCellTextColor; + /** + * Whether to not wrap the text in the cell. + */ + noWrap?: boolean; } type TableCellText = { @@ -113,6 +121,17 @@ type TableCellLink = { isExternal?: boolean; }; +type TableCellChildren = { + /** + * The type of the cell. + */ + type: TableCellType.Children; + /** + * The children of the cell. + */ + children?: React.ReactNode; +}; + export type TableCellProps = TableCellBaseProps & ( | TableCellText @@ -122,12 +141,18 @@ export type TableCellProps = TableCellBaseProps & | TableCellCheckbox | TableCellPlaceholder | TableCellLink + | TableCellChildren ); export function TableCell(props: TableCellProps): JSX.Element { - const { type, label, hasLastBorderNoneClass, isContentCentered } = props; + const { + type, + label, + hasLastBorderNoneClass, + isContentCentered, + textColor: textColorClass = TableCellTextColor.Default, + } = props; - const textColorClass = 'text-neutral-40 dark:text-neutral-60'; const textSizeClass = 'text-body-md'; async function handleCopyClick(event: React.MouseEvent<HTMLButtonElement, MouseEvent>) { @@ -143,12 +168,19 @@ export function TableCell(props: TableCellProps): JSX.Element { } const Cell = () => { + const { noWrap } = props; switch (type) { case TableCellType.Text: const { supportingLabel } = props; return ( <div className="flex flex-row items-baseline gap-1"> - <span className={cx(textColorClass, textSizeClass)}>{label}</span> + <span + className={cx(textColorClass, textSizeClass, { + 'whitespace-nowrap': noWrap, + })} + > + {label} + </span> {supportingLabel && ( <span className="text-body-sm text-neutral-60 dark:text-neutral-40"> {supportingLabel} @@ -176,6 +208,7 @@ export function TableCell(props: TableCellProps): JSX.Element { return <Badge type={badgeType} label={label} />; case TableCellType.AvatarText: const { leadingElement } = props; + return ( <div className={cx('flex items-center gap-x-2.5', textColorClass)}> {leadingElement} @@ -203,11 +236,16 @@ export function TableCell(props: TableCellProps): JSX.Element { href={to} target={isExternal ? '_blank' : '_self'} rel="noopener noreferrer" - className={cx('text-primary-30 dark:text-primary-80', textSizeClass)} + className={cx('text-primary-30 dark:text-primary-80', textSizeClass, { + 'whitespace-nowrap': noWrap, + })} > {label} </a> ); + case TableCellType.Children: + const { children } = props; + return children; default: return null; } diff --git a/apps/ui-kit/src/lib/components/molecules/table-cell/table-cell.enums.ts b/apps/ui-kit/src/lib/components/molecules/table-cell/table-cell.enums.ts index 856dcf3f30e..c89759317d8 100644 --- a/apps/ui-kit/src/lib/components/molecules/table-cell/table-cell.enums.ts +++ b/apps/ui-kit/src/lib/components/molecules/table-cell/table-cell.enums.ts @@ -9,4 +9,10 @@ export enum TableCellType { Checkbox = 'checkbox', Placeholder = 'placeholder', Link = 'link', + Children = 'children', +} + +export enum TableCellTextColor { + Default = 'text-neutral-40 dark:text-neutral-60', + Dark = 'text-neutral-10 dark:text-neutral-92', } diff --git a/apps/ui-kit/src/lib/components/molecules/table-header-cell/TableHeaderCell.tsx b/apps/ui-kit/src/lib/components/molecules/table-header-cell/TableHeaderCell.tsx index 722e3235b95..84beb087ecb 100644 --- a/apps/ui-kit/src/lib/components/molecules/table-header-cell/TableHeaderCell.tsx +++ b/apps/ui-kit/src/lib/components/molecules/table-header-cell/TableHeaderCell.tsx @@ -105,7 +105,13 @@ export function TableHeaderCell({ onCheckedChange={onCheckboxChange} /> ) : ( - <span>{label}</span> + <span + className={cx({ + 'text-left': !isContentCentered, + })} + > + {label} + </span> )} {hasSort && sortOrder === TableHeaderCellSortOrder.Asc && ( <SortByUp className="cursor-pointer" onClick={handleSort} /> diff --git a/apps/ui-kit/src/lib/tailwind/constants/colors.constants.ts b/apps/ui-kit/src/lib/constants/colors.constants.ts similarity index 100% rename from apps/ui-kit/src/lib/tailwind/constants/colors.constants.ts rename to apps/ui-kit/src/lib/constants/colors.constants.ts diff --git a/apps/ui-kit/src/lib/constants/index.ts b/apps/ui-kit/src/lib/constants/index.ts new file mode 100644 index 00000000000..8b691fd8ff1 --- /dev/null +++ b/apps/ui-kit/src/lib/constants/index.ts @@ -0,0 +1,4 @@ +// Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +export * from './colors.constants'; diff --git a/apps/ui-kit/src/lib/index.ts b/apps/ui-kit/src/lib/index.ts index 0e37afefc94..4457ead55fc 100644 --- a/apps/ui-kit/src/lib/index.ts +++ b/apps/ui-kit/src/lib/index.ts @@ -3,4 +3,5 @@ export * from './tailwind'; export * from './components'; +export * from './constants'; export * from './enums'; diff --git a/apps/ui-kit/src/lib/tailwind/base.preset.ts b/apps/ui-kit/src/lib/tailwind/base.preset.ts index 9608070bda8..f7ee5e37a5e 100644 --- a/apps/ui-kit/src/lib/tailwind/base.preset.ts +++ b/apps/ui-kit/src/lib/tailwind/base.preset.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { Config } from 'tailwindcss'; -import { IOTA_PRIMITIVES_COLOR_PALETTE, SHADER_COLOR_PALETTE } from './constants/colors.constants'; +import { IOTA_PRIMITIVES_COLOR_PALETTE, SHADER_COLOR_PALETTE } from '../constants/colors.constants'; import { CUSTOM_FONT_SIZES, BORDER_RADIUS, diff --git a/apps/ui-kit/src/lib/tailwind/constants/index.ts b/apps/ui-kit/src/lib/tailwind/constants/index.ts index a481235f30c..2adc80fcca0 100644 --- a/apps/ui-kit/src/lib/tailwind/constants/index.ts +++ b/apps/ui-kit/src/lib/tailwind/constants/index.ts @@ -1,7 +1,6 @@ // Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -export * from './colors.constants'; export * from './scaling.constants'; export * from './fontSizes.constants'; export * from './variable-spacing.constants'; diff --git a/apps/ui-kit/src/storybook/stories/atoms/LabelText.stories.tsx b/apps/ui-kit/src/storybook/stories/atoms/LabelText.stories.tsx index f94d22039e5..d9c99286cdc 100644 --- a/apps/ui-kit/src/storybook/stories/atoms/LabelText.stories.tsx +++ b/apps/ui-kit/src/storybook/stories/atoms/LabelText.stories.tsx @@ -22,7 +22,6 @@ export const Default: Story = { text: '12,000.00', label: 'Label', size: LabelTextSize.Medium, - showSupportingLabel: true, supportingLabel: 'IOTA', isCentered: false, }, @@ -40,9 +39,6 @@ export const Default: Story = { supportingLabel: { control: 'text', }, - showSupportingLabel: { - control: 'boolean', - }, text: { control: 'text', }, diff --git a/apps/ui-kit/src/storybook/stories/design-tokens/colors.stories.mdx b/apps/ui-kit/src/storybook/stories/design-tokens/colors.stories.mdx index 18afbd591fe..94f3f51adaf 100644 --- a/apps/ui-kit/src/storybook/stories/design-tokens/colors.stories.mdx +++ b/apps/ui-kit/src/storybook/stories/design-tokens/colors.stories.mdx @@ -2,7 +2,7 @@ import { Meta, ColorPalette, ColorItem } from '@storybook/blocks'; import { IOTA_PRIMITIVES_COLOR_PALETTE, SHADER_COLOR_PALETTE, -} from '../../../lib/tailwind/constants/colors.constants'; +} from '../../../lib/constants/colors.constants'; <Meta title="Design Tokens/Colors" /> diff --git a/apps/wallet-dashboard/package.json b/apps/wallet-dashboard/package.json index 3e79a7a28fa..71591c967e1 100644 --- a/apps/wallet-dashboard/package.json +++ b/apps/wallet-dashboard/package.json @@ -21,7 +21,7 @@ "@iota/iota-sdk": "workspace:*", "@tanstack/react-query": "^5.0.0", "@tanstack/react-virtual": "^3.5.0", - "next": "14.2.3", + "next": "14.2.10", "react": "^18.3.1", "zustand": "^4.4.1" }, diff --git a/docker/fullnode/README.md b/docker/fullnode/README.md index 36f03c63b2a..eea6c38606f 100644 --- a/docker/fullnode/README.md +++ b/docker/fullnode/README.md @@ -10,21 +10,25 @@ Follow the steps in this Readme to install and configure a Iota Full node for te - [Install Docker](https://docs.docker.com/get-docker/) - [Install Docker Compose](https://docs.docker.com/compose/install/) -- Download the Full node [docker-compose.yaml](https://github.com/iotaledger/iota/blob/main/docker/fullnode/docker-compose.yaml) file. +- Download the Full node [docker-compose.yaml](https://github.com/iotaledger/iota/blob/develop/docker/fullnode/docker-compose.yaml) file. ## Configure Iota Full node -Download the latest version of the Iota Full node configuration file [fullnode-template.yaml](https://github.com/iotaledger/iota/raw/main/crates/iota-config/data/fullnode-template.yaml). Use the following command to download the file: +Download the latest version of the Iota Full node configuration file [fullnode-template.yaml](https://github.com/iotaledger/iota/raw/develop/crates/iota-config/data/fullnode-template.yaml). Use the following command to download the file: ```shell -wget https://github.com/iotaledger/iota/raw/main/crates/iota-config/data/fullnode-template.yaml +wget https://github.com/iotaledger/iota/raw/develop/crates/iota-config/data/fullnode-template.yaml ``` +To ensure you add the appropriate peers for your full node, please refer to the instructions provided at the following link: +https://docs.iota.org/operator/iota-full-node#set-up-from-source and proceed with step 4. + ### Download the Iota genesis blob -The genesis blob contains the information that defined the Iota network configuration. Before you can start the Full node, you need to download the most recent file to ensure compatibility with the version of Iota you use. Use the following command to download the [genesis.blob](https://github.com/iotaledger/iota-genesis/raw/main/devnet/genesis.blob) from the `devnet` branch of the Iota repository: +The genesis blob contains the information that defined the Iota network configuration. Before you can start the Full node, you need to download the most recent file to ensure compatibility with the version of Iota you use. -`wget https://github.com/iotaledger/iota-genesis/raw/main/devnet/genesis.blob` +To download the appropriate genesis.blob file, please refer to the instructions provided at the following link: +https://docs.iota.org/operator/iota-full-node#set-up-from-source. and proceed with step 3. ## Start your Iota Full node @@ -42,7 +46,7 @@ After the Full node starts you can test the JSON-RPC interfaces. ## View activity on your local Full node with Iota Explorer -Iota Explorer supports connecting to a local network. To view activity on your local Full node, open the URL: [https://explorer.iota.io/?network=local](https://explorer.iota.io/?network=local). +Iota Explorer supports connecting to a local network. To view activity on your local Full node, open the URL: [https://explorer.iota.org/?network=local](https://explorer.iota.org/?network=local). You can also change the network that Iota Explorer connects to by select it in the Iota Explorer interface. diff --git a/docs/content/about-iota/iota-architecture/iota-architecture.mdx b/docs/content/about-iota/iota-architecture/iota-architecture.mdx index 6fffb07ff89..540a16fa536 100644 --- a/docs/content/about-iota/iota-architecture/iota-architecture.mdx +++ b/docs/content/about-iota/iota-architecture/iota-architecture.mdx @@ -34,7 +34,7 @@ The following diagram describes the architectural structure for IOTA's solution. The core components are: -- [Execution Layer](../execution-architecture/execution-layer.mdx) +- [Execution Layer](../../references/execution-architecture/execution-layer.mdx) - [IOTA Node](../../operator/iota-full-node.mdx) - [IOTA RPC](../../references/iota-api) - [IOTA CLI](../../references/cli) diff --git a/docs/content/developer/cryptography/on-chain/ecvrf.mdx b/docs/content/developer/cryptography/on-chain/ecvrf.mdx index ac1c28bf760..308dedaf339 100644 --- a/docs/content/developer/cryptography/on-chain/ecvrf.mdx +++ b/docs/content/developer/cryptography/on-chain/ecvrf.mdx @@ -52,7 +52,7 @@ module math::ecvrf_test { use iota::event; /// Event on whether the output is verified - struct VerifiedEvent has copy, drop { + public struct VerifiedEvent has copy, drop { is_verified: bool, } diff --git a/docs/content/developer/cryptography/on-chain/hashing.mdx b/docs/content/developer/cryptography/on-chain/hashing.mdx index 3828658c8be..ed63b7d95eb 100644 --- a/docs/content/developer/cryptography/on-chain/hashing.mdx +++ b/docs/content/developer/cryptography/on-chain/hashing.mdx @@ -22,10 +22,9 @@ module test::hashing_std { use iota::object::{Self, UID}; use iota::tx_context::TxContext; use iota::transfer; - use std::vector; /// Object that holds the output hash value. - struct Output has key, store { + public struct Output has key, store { id: UID, value: vector<u8> } @@ -49,10 +48,9 @@ module test::hashing_iota { use iota::object::{Self, UID}; use iota::tx_context::TxContext; use iota::transfer; - use std::vector; /// Object that holds the output hash value. - struct Output has key, store { + public struct Output has key, store { id: UID, value: vector<u8> } diff --git a/docs/content/developer/developer.mdx b/docs/content/developer/developer.mdx index 10774af912b..aa7aca661d6 100644 --- a/docs/content/developer/developer.mdx +++ b/docs/content/developer/developer.mdx @@ -5,24 +5,24 @@ description: Guides and documents for developers on the IOTA network. Whether yo The developer section is meant to introduce you to the Move programming language and its implementation on the IOTA network through examples, tasks, and conceptual content. This contains everything a developer needs to get started developing on top of the IOTA network. -## Getting started +## Getting Started -If you are completely new to Move, you should start with the aptly named Getting Started section. Topics in that section introduce you to the IOTA monorepo, guide you through installing IOTA binaries, and introduce you to some key core concepts of blockchain technology, particularly how they relate to IOTA. +If you are completely new to Move, you should start with the aptly named Getting Started section. Topics in that section introduce you to the IOTA monorepo, guide you through installing IOTA binaries, and introduce you to some key core concepts of blockchain technology, particularly how they relate to IOTA. This sections contains everything you need to get your first dApp built and deployed. Go to [Getting Started](getting-started/getting-started.mdx). -## Your first dApp - -If you prefer to jump right in to coding (after installing IOTA, of course), then the Your First dApp is the place for you. These topics show you how to work with Move packages and get them published on-chain. - -Go to [Your First IOTA dApp](getting-started/create-a-package.mdx). - ## IOTA 101 The IOTA 101 section introduces the basics of IOTA that help you create smart contracts. These topics assume you are familiar with Move and the IOTA blockchain. Go to [IOTA 101](iota-101.mdx). +## Standards + +Utilizing standards while developing applications is very important for composability. In this section you can find out all about the standards within the IOTA Move ecosystem for dealing with tokens, NFT like objects, and wallets. + +Go to the [Standards](/developer/standards). + ## IOTA compared to EVM If you are familiar with EVM/Solidity and want to work with IOTA and Move this section is for you. These topics describe the differences between a traditional EVM chain and way of working compared to IOTA Move based smart contracts. Together with some common implementation examples the nuances between the different ways of working are explained. @@ -35,19 +35,25 @@ The Cryptography section demonstrates how to secure your smart contracts with cr Go to [Cryptography](cryptography.mdx). -## Standards - -Utilizing standards while developing applications is very important for composability. In this section you can find out all about the standards within the IOTA Move ecosystem for dealing with tokens, NFT like objects, and wallets. - -Go to the [Standards](/developer/standards). - ## Advanced Topics The Advanced Topics section includes guides for advanced solutions (like asset tokenization). These topics assume you are familiar with Move and the IOTA blockchain. Go to the [Advanced Topics](advanced.mdx). -## Developer cheat sheet +## Migrating from IOTA/Shimmer Stardust + +IOTA Stardust becomes IOTA Rebased, and with it a lot of changes. Most assets are just available on the IOTA Rebased chain once it's available without any manual work but for integrations and in some situations you might need to migrate. This section covers the details of the migration and how you can prepare your integration to be IOTA Rebased compatible. + +Go to [Migrating from IOTA/Shimmer Stardust](stardust/stardust-migration.mdx). + +## Exchange Integration + +This section contains the technical details needed to integrate IOTA on a exchange. + +Go to [Exchange integration](exchange-integration/exchange-integration.mdx). + +## Developer Cheat Sheet The cheat sheet is a compact overview of solutions for common problems and contains information on how to avoid common pitfalls for IOTA Move developers. This page contains important information that might get lost in the quantity of content available. Use this often-updated page to see around corners when starting a Move project or to refresh your memory on important concepts to be mindful of. @@ -59,14 +65,9 @@ Everything you need to know about our Layer 2 EVM Support, including working wit Go to [EVM Smart Contracts](iota-evm/introduction.mdx). -## Migrating from IOTA/Shimmer Stardust - -IOTA Stardust becomes IOTA Rebased, and with it a lot of changes. Most assets are just available on the IOTA Rebased chain once it's available without any manual work but for integrations and in some situations you might need to migrate. This section covers the details of the migration and how you can prepare your integration to be IOTA Rebased compatible. - -Go to [Migrating from IOTA/Shimmer Stardust](stardust/stardust-migration.mdx). +## Decentralized Identity -## Exchange integration +IOTA also offers a Decentralized Identity framework which can be utilized to provide and use digital decentralized identities for People, Organizations, Things and Objects. -This section contains the technical details needed to integrate IOTA on a exchange. +Go to the [IOTA Identity Framework](iota-identity/welcome.mdx) section. -Go to [Exchange integration](exchange-integration/exchange-integration.mdx). diff --git a/docs/content/developer/evm-to-move/creating-token.mdx b/docs/content/developer/evm-to-move/creating-token.mdx index f3c8dbf6797..f8597fd1903 100644 --- a/docs/content/developer/evm-to-move/creating-token.mdx +++ b/docs/content/developer/evm-to-move/creating-token.mdx @@ -36,13 +36,12 @@ The initial creation of `Coin` takes place by minting these coins. This is usual ```move title="examples/Exampletoken.move" module examples::exampletoken { - use std::option; use iota::coin; use iota::transfer; use iota::tx_context::{Self, TxContext}; /// One-Time-Witness of kind: `Coin<package_object::exampletoken::EXAMPLETOKEN>` - struct EXAMPLETOKEN has drop {} + public struct EXAMPLETOKEN has drop {} fun init(witness: EXAMPLETOKEN, ctx: &mut TxContext) { let (treasurycap, metadata) = coin::create_currency( @@ -71,7 +70,7 @@ A `module` is defined (`exampletoken`) as part of the `examples` package (module After the aliases, we see an empty struct defined: ```move -struct EXAMPLETOKEN has drop {} +public struct EXAMPLETOKEN has drop {} ``` This is the definition of the so-called [One-Time-Witness](../iota-101/move-overview/one-time-witness.mdx). Together with the `init` function definition, this ensures that this `Coin` will only be created once and never more on this chain. diff --git a/docs/content/developer/getting-started/connect.mdx b/docs/content/developer/getting-started/connect.mdx index d897fdc7ced..ee23e1c8e02 100644 --- a/docs/content/developer/getting-started/connect.mdx +++ b/docs/content/developer/getting-started/connect.mdx @@ -10,11 +10,13 @@ import AlphaNet from "../../_snippets/alphanet.mdx"; ## IOTA CLI -IOTA provides [IOTA command line interface (CLI)](/references/cli/client.mdx) to interact with [IOTA networks](#iota-networks): +IOTA provides the [IOTA command line interface (CLI)](/references/cli/client.mdx) to interact with [IOTA networks](#iota-networks), it does the following and more: - Create and manage your private keys -- Create example NFTs - Call and publish Move modules +- Compile and test Move modules +- Create and execute programmable transaction blocks ([PTBs](/references/cli/ptb.mdx)) +- Interact with testnet/devnet faucets You can use the [CLI](iota-environment.mdx#iota-cli) or [SDKs](iota-environment.mdx#iota-sdks) to send transactions and read requests from using the [JSON-RPC](../../references/iota-api/json-rpc-format.mdx) and the following @@ -90,6 +92,12 @@ Select key scheme to generate keypair (0 for ed25519, 1 for secp256k1, 2: for se Finally, you will be prompted to select the key scheme you want to use. After this, you will receive a message that states the selected key-scheme, the generated address and your secret recovery phrase. +:::tip Signature scheme selection + +If you are unsure which scheme to use just go with the default ed25519 scheme (option 0). + +::: + ```bash Generated new keypair for address with scheme "ed25519" [0xb9c83a8b40d3263c9ba40d551514fbac1f8c12e98a4005a0dac072d3549c2442] Secret Recovery Phrase : [hat become demise beyond history wood stage add nice list jaguar legend] diff --git a/docs/content/developer/getting-started/create-a-package.mdx b/docs/content/developer/getting-started/create-a-package.mdx index 7c9b61b791b..653e2ce44af 100644 --- a/docs/content/developer/getting-started/create-a-package.mdx +++ b/docs/content/developer/getting-started/create-a-package.mdx @@ -31,7 +31,7 @@ In `.toml` files, use the hash mark (`#`) to denote a comment. ```toml title="my_first_package/Move.toml" [package] name = "my_first_package" -edition = "2024.beta" # edition = "legacy" to use legacy (pre-2024) Move +edition = "2024.beta" # edition # license = "" # e.g., "MIT", "GPL", "Apache 2.0" # authors = ["..."] # e.g., ["Joe Smith (joesmith@noemail.com)", "John Snow (johnsnow@noemail.com)"] @@ -43,7 +43,7 @@ Iota = { git = "https://github.com/iotaledger/iota.git", subdir = "crates/iota-f # MyRemotePackage = { git = "https://some.remote/host.git", subdir = "remote/path", rev = "main" } # For local dependencies use `local = path`. Path is relative to the package root -# Local = { local = "../path/to" } +# Iota = { local = "../path/to/iota/crates/iota-framework/packages/iota-framework" } # To resolve a version conflict and force a specific version for dependency # override use `override = true` @@ -67,6 +67,12 @@ my_first_package = "0x0" # alice = "0xB0B" ``` +:::tip Using a local version of IOTA + +For local testnet development and testing it is recommended to use the local dependency of the `Iota` framework for faster and more reliable builds. See the commented line in the example above as an example pointing towards your local checkout of the `iota` repository. + +::: + ### Package The `[package]` section describes the package. By default, the `iota move new` command populates only the `name` value @@ -83,13 +89,13 @@ repository URL or a path to the local directory. ```rust # git repository -iota = { git = "https://github.com/iotaledger/iota.git", subdir = "crates/iota-framework/packages/iota-framework", rev = "framework/testnet" } +Iota = { git = "https://github.com/iotaledger/iota.git", subdir = "crates/iota-framework/packages/iota-framework", rev = "framework/testnet" } # local directory MyPackage = { local = "../my-package" } ``` -Packages also import addresses from other packages. For example, the IOTA dependency adds the `std` and `iota` addresses +Packages also import addresses from other packages. For example, the `Iota` dependency adds the `std` and `iota` addresses to the project. These addresses can be used in the code as aliases for the addresses. ### Resolving Version Conflicts with `override` @@ -100,7 +106,7 @@ the `[dependencies]` section will be used instead of the one specified in the de ```rust [dependencies] -iota = { override = true, git = "https://github.com/iotaledger/iota.git", subdir = "crates/iota-framework/packages/iota-framework", rev = "framework/testnet" } +Iota = { override = true, git = "https://github.com/iotaledger/iota.git", subdir = "crates/iota-framework/packages/iota-framework", rev = "framework/testnet" } ``` ### Dev-dependencies diff --git a/docs/content/developer/getting-started/get-address.mdx b/docs/content/developer/getting-started/get-address.mdx index b88e4b57fe2..8aa74e7d322 100644 --- a/docs/content/developer/getting-started/get-address.mdx +++ b/docs/content/developer/getting-started/get-address.mdx @@ -67,7 +67,7 @@ IOTA provides multiple ways to obtain an IOTA address. The following are the two :::note Supported Address Types -IOTA supports multiple cryptographic algorithms for account generation. The two supported curves +IOTA supports multiple signature schemes for account generation. The currently supported curves are `ed25519`, `secp256k1`, and `secp256r1`. ::: diff --git a/docs/content/developer/getting-started/iota-install.mdx b/docs/content/developer/getting-started/iota-install.mdx index d069f0d9591..2c5d905d88e 100644 --- a/docs/content/developer/getting-started/iota-install.mdx +++ b/docs/content/developer/getting-started/iota-install.mdx @@ -24,9 +24,9 @@ always [build the binaries yourself from source](#install-from-source). IOTA supports the following operating systems: -- Linux - Ubuntu version 20.04 (Bionic Beaver) -- macOS - macOS Monterey -- Microsoft Windows - Windows 10 and 11 +- Linux (Ubuntu/Debian recommended) +- macOS +- Microsoft Windows (10+) {/* TODO: Re-enable and check if we have packages published */} {/* @@ -76,7 +76,7 @@ install the necessary binaries. You should start with the main IOTA binary. 2. iota-faucet-`<OS>`-`<ARCHITECTURE>`: Local faucet to mint coins on a local network. 3. iota-indexer-`<OS>`-`<ARCHITECTURE>`: An indexer for a local IOTA network. 4. iota-node-`<OS>`-`<ARCHITECTURE>`: Run a local node. -5. iota-test-validator-`<OS>`-`<ARCHITECTURE>`: Run test validators on a local network for development. +5. iota-test-validator-`<OS>`-`<ARCHITECTURE>`: Run test validators on a local network for development, including indexer and faucet. 6. iota-tool-`<OS>`-`<ARCHITECTURE>`: Provides utilities for IOTA. :::note diff --git a/docs/content/developer/getting-started/local-network.mdx b/docs/content/developer/getting-started/local-network.mdx index 6c74dae57d9..df113e650b9 100644 --- a/docs/content/developer/getting-started/local-network.mdx +++ b/docs/content/developer/getting-started/local-network.mdx @@ -5,12 +5,12 @@ tags: [ how-to, install, setup, cli, typescript, sdk, testing ] # Local Development You can create a local IOTA network to develop and test your dApps with the latest changes in the IOTA repository. You -can set it up using the `iota-test-validator` binary, which will start a local IOTA Full node, an IOTA validator, and a +can set it up using the `iota-test-validator` binary, which will start a local IOTA network consisting of 4 IOTA validators with indexer and a test token faucet. ## Prerequisites -You should [install IOTA](iota-install.mdx) to interact with the local node. +You should [install the IOTA CLI tool](iota-install.mdx) to interact with the local node. ## Start a Local Network @@ -165,7 +165,7 @@ The response resembles the following, but with different IDs: ### Prerequisites -* [pnpm](https://pnpm.io/installation). +* [pnpm](https://pnpm.io/installation) ### Install Dependencies diff --git a/docs/content/operator/iota-full-node.mdx b/docs/content/operator/iota-full-node.mdx index 7502a475929..ecafd65f858 100644 --- a/docs/content/operator/iota-full-node.mdx +++ b/docs/content/operator/iota-full-node.mdx @@ -13,13 +13,13 @@ IOTA Full nodes validate blockchain activities, including transactions, checkpoi This role enables validators to focus on servicing and processing transactions. When a validator commits a new set of transactions (or a block of transactions), the validator pushes that block to all connected Full nodes that then service the queries from clients. -## Features +## Features IOTA Full nodes: - Track and verify the state of the blockchain, independently and locally. - Serve read requests from clients. -## State synchronization +## State synchronization IOTA Full nodes sync with validators to receive new transactions on the network. A transaction requires a few round trips to 2f+1 validators to form a transaction certificate (TxCert). @@ -32,7 +32,7 @@ This synchronization process includes: This synchronization process requires listening to at a minimum 2f+1 validators to ensure that a Full node has properly processed all new transactions. IOTA will improve the synchronization process with the introduction of checkpoints and the ability to synchronize with other Full nodes. -## Architecture +## Architecture An IOTA Full node is essentially a read-only view of the network state. Unlike validator nodes, Full nodes cannot sign transactions, although they can validate the integrity of the chain by re-executing transactions that a quorum of validators previously committed. @@ -40,11 +40,11 @@ Today, an IOTA Full node maintains the full history of the chain. Validator nodes store only the latest transactions on the frontier of the object graph (for example, transactions with >0 unspent output objects). -## Full node setup +## Full node setup Follow the instructions here to run your own IOTA Full node. -### Hardware requirements +### Hardware requirements Suggested minimum hardware to run an IOTA Full node: @@ -52,7 +52,7 @@ Suggested minimum hardware to run an IOTA Full node: - RAM: 128 GB - Storage (SSD): 4 TB NVMe drive -### Software requirements +### Software requirements IOTA recommends running IOTA Full nodes on Linux. IOTA supports the Ubuntu and Debian distributions. You can also run an IOTA Full node on macOS. @@ -78,15 +78,15 @@ clang \ cmake ``` -## Configure a Full node +## Configure a Full node You can configure an IOTA Full node either using Docker or by building from source. -### Using Docker Compose +### Using Docker Compose Follow the instructions in the [Full node Docker Readme](https://github.com/iotaledger/iota/tree/develop/docker/fullnode#readme) to run an IOTA Full node using Docker, including [resetting the environment](https://github.com/iotaledger/iota/tree/develop/docker/fullnode#reset-the-environment). -### Setting up a local IOTA repository +### Setting up a local IOTA repository You must get the latest source files from the IOTA GitHub repository. 1. Set up your fork of the IOTA repository: @@ -109,23 +109,23 @@ Open a terminal or console to the `iota` directory you downloaded in the previou 1. Make a copy of the [Full node YAML template](https://github.com/iotaledger/iota/blob/develop/crates/iota-config/data/fullnode-template.yaml): `cp crates/iota-config/data/fullnode-template.yaml fullnode.yaml` 1. Download the genesis blob for the network to use: - - [Devnet genesis blob](https://github.com/iotaledger/iota/TODO): - `curl -fLJO TODO` + - [Alphanet genesis blob](https://dbfiles.iota-rebased-alphanet.iota.cafe/genesis.blob): + `curl -fLJO https://dbfiles.iota-rebased-alphanet.iota.cafe/genesis.blob` - [Testnet genesis blob](https://github.com/iotaledger/iota/TODO): `curl -fLJO TODO` - [Mainnet genesis blob](https://github.com/iotaledger/iota/TODO): `curl -fLJO TODO` -1. For Testnet or Mainnet: Edit the `fullnode.yaml` file to include peer nodes for state synchronization. Append the following to the end of the current configuration: +1. For Alphanet or Testnet: Edit the `fullnode.yaml` file to include peer nodes for state synchronization. Append the following to the end of the current configuration: <Tabs groupId="network"> - <TabItem label="Mainnet" value="mainnet"> + <TabItem label="Alphanet" value="alphanet"> ```yaml p2p-config: seed-peers: - - address: TODO # Example: /dns/mel-00.mainnet.iota.io/udp/8084 - peer-id: TODO # Example: d32b55bdf1737ec415df8c88b3bf91e194b59ee3127e3f38ea46fd88ba2e7849 + - address: /dns/access-0.r.iota-rebased-alphanet.iota.cafe/udp/8084 + peer-id: 10cbea76ea5ec3f7ee827f0c11f612f0059949127876dd964b09304bf8808d18 ``` </TabItem> @@ -141,7 +141,7 @@ Open a terminal or console to the `iota` directory you downloaded in the previou </TabItem> </Tabs> - + 1. Optional: Skip this step to accept the default paths to resources. Edit the fullnode.yaml file to use custom paths. 1. Update the `db-path` field with the path to the Full node database. `db-path: "/db-files/iota-fullnode"` @@ -159,7 +159,7 @@ Run the following command to compile the `iota-node`. cargo run --release --bin iota-node ``` -### Starting services +### Starting services At this point, your IOTA Full node is ready to connect to the IOTA network. @@ -172,7 +172,7 @@ If your setup is successful, your IOTA Full node is now connected to the appropr Your Full node serves the read endpoints of the IOTA JSON-RPC API at: `http://127.0.0.1:9000`. -### Troubleshooting +### Troubleshooting If, during the compilation step, you receive a `cannot find -lpq` error, you are missing the `libpq` library. Use `sudo apt-get install libpq-dev` to install on Linux, or `brew install libpq` on MacOS. After you install on MacOS, create a Homebrew link using `brew link --force libpq`. For further context, reference the [issue on Stack Overflow](https://stackoverflow.com/questions/70313347/ld-library-not-found-for-lpq-when-build-rust-in-macos?rq=1). If you receive the following error: @@ -187,17 +187,17 @@ Then update the metrics address in your fullnode.yaml file to use port `9180`. metrics-address: "0.0.0.0:9180" ``` -## Monitoring +## Monitoring Monitor your Full node using the instructions in the _Node Monitoring and Metrics_ section. The default metrics port is `9184`. To change the port, edit your `fullnode.yaml` file. -## Update your Full node +## Update your Full node Whenever IOTA releases a new version, you must update your Full node with the release to ensure compatibility with the network it connects to. For example, if you use IOTA Testnet you should install the version of IOTA running on IOTA Testnet. -### Update with Docker Compose +### Update with Docker Compose Follow the instructions to [reset the environment](https://github.com/iotaledger/iota/tree/develop/docker/fullnode#reset-the-environment), namely by running the command: @@ -205,7 +205,7 @@ Follow the instructions to [reset the environment](https://github.com/iotaledger docker-compose down --volumes ``` -### Update from source +### Update from source If you followed the instructions for Building from Source, use the following steps to update your Full node: @@ -241,13 +241,13 @@ If you followed the instructions for Building from Source, use the following ste ```shell ./target/release/iota-node --config-path fullnode.yaml ``` - + Your Full node starts on: http://127.0.0.1:9000. ## Object pruning {#object-pruning} -IOTA adds new object versions to the database as part of transaction execution. This makes previous versions ready for -garbage collection. However, without pruning, this can result in database performance degradation and requires large +IOTA adds new object versions to the database as part of transaction execution. This makes previous versions ready for +garbage collection. However, without pruning, this can result in database performance degradation and requires large amounts of storage space. IOTA identifies the objects that are eligible for pruning in each checkpoint, and then performs the pruning in the background. @@ -255,7 +255,7 @@ You can enable pruning for an IOTA node by adding the `authority-store-pruning-c ```yaml authority-store-pruning-config: - # Number of epoch dbs to keep + # Number of epoch dbs to keep # Not relevant for object pruning num-latest-epoch-dbs-to-retain: 3 # The amount of time, in seconds, between running the object pruning task. @@ -264,16 +264,16 @@ authority-store-pruning-config: # Number of epochs to wait before performing object pruning. # When set to 0, IOTA prunes old object versions as soon # as possible. This is also called *aggressive pruning*, and results in the most effective - # garbage collection method with the lowest disk usage possible. + # garbage collection method with the lowest disk usage possible. # This is the recommended setting for IOTA Validator nodes since older object versions aren't # necessary to execute transactions. # When set to 1, IOTA prunes only object versions from transaction checkpoints - # previous to the current epoch. In general, when set to N (where N >= 1), IOTA prunes - # only object versions from checkpoints up to `current - N` epoch. - # It is therefore possible to have multiple versions of an object present - # in the database. This setting is recommended for IOTA Full nodes as they might need to serve + # previous to the current epoch. In general, when set to N (where N >= 1), IOTA prunes + # only object versions from checkpoints up to `current - N` epoch. + # It is therefore possible to have multiple versions of an object present + # in the database. This setting is recommended for IOTA Full nodes as they might need to serve # RPC requests that require looking up objects by ID and Version (rather than just the latest - # version). However, if your Full node does not serve RPC requests you should then also enable + # version). However, if your Full node does not serve RPC requests you should then also enable # aggressive pruning. num-epochs-to-retain: 0 # Advanced setting: Maximum number of checkpoints to prune in a batch. The default @@ -301,9 +301,9 @@ authority-store-pruning-config: max-checkpoints-in-batch: 10 max-transactions-in-batch: 1000 # Number of epochs to wait before performing transaction pruning. - # When this is N (where N >= 2), IOTA prunes transactions and effects from + # When this is N (where N >= 2), IOTA prunes transactions and effects from # checkpoints up to the `current - N` epoch. IOTA never prunes transactions and effects from the current and - # immediately prior epoch. N = 2 is a recommended setting for IOTA Validator nodes and IOTA Full nodes that don't + # immediately prior epoch. N = 2 is a recommended setting for IOTA Validator nodes and IOTA Full nodes that don't # serve RPC requests. num-epochs-to-retain-for-checkpoints: 2 # Ensures that individual database files periodically go through the compaction process. diff --git a/docs/content/references/contribute/contribute-to-iota-repos.mdx b/docs/content/references/contribute/contribute-to-iota-repos.mdx index 134e31484b6..9c4a678c7f8 100644 --- a/docs/content/references/contribute/contribute-to-iota-repos.mdx +++ b/docs/content/references/contribute/contribute-to-iota-repos.mdx @@ -18,8 +18,3 @@ To report an issue with IOTA, [create an issue](https://github.com/iotaledger/io To contribute to IOTA source code or documentation, you need only a GitHub account. You can commit updates and then submit a PR directly from the Github website, or create a fork of the repo to your local environment and use your favorite tools to make changes. Always submit PRs to the `main` branch. See [IOTA Environment Setup](/developer/getting-started/iota-environment.mdx) for instructions on forking the IOTA repository, if necessary. - -## Contribute via the IOTA Improvement Proposal (SIP) process {#SIP} - -The IOTA Network is an open-source, decentralized, and permissionless protocol that welcomes community contributions. If you have an idea regarding a core protocol upgrade, the best way to make your voice heard is via submitting a IOTA Improvement Proposal (SIP). For more information on SIPs, see [Contribute to IOTA through SIPs](https://blog.iota.io/iota-improvement-proposals-sips/). - diff --git a/docs/content/references/contribute/localize-iota-docs.mdx b/docs/content/references/contribute/localize-iota-docs.mdx deleted file mode 100644 index 3827502075e..00000000000 --- a/docs/content/references/contribute/localize-iota-docs.mdx +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Localize IOTA Documentation -slug: /localize-iota-docs ---- - -The IOTA documentation can be localized (translated) into any language of your choosing. The localization platform utilized is Crowdin. For more information regarding the localization process please see [here](https://support.crowdin.com/crowdin-intro/). diff --git a/docs/content/about-iota/execution-architecture/adapter.mdx b/docs/content/references/execution-architecture/adapter.mdx similarity index 100% rename from docs/content/about-iota/execution-architecture/adapter.mdx rename to docs/content/references/execution-architecture/adapter.mdx diff --git a/docs/content/about-iota/execution-architecture/execution-layer.mdx b/docs/content/references/execution-architecture/execution-layer.mdx similarity index 87% rename from docs/content/about-iota/execution-architecture/execution-layer.mdx rename to docs/content/references/execution-architecture/execution-layer.mdx index 7d5a5782bfd..c0f04f857b3 100644 --- a/docs/content/about-iota/execution-architecture/execution-layer.mdx +++ b/docs/content/references/execution-architecture/execution-layer.mdx @@ -9,4 +9,4 @@ It includes: - The [IOTA Execution Crate](iota-execution.mdx). - The [Adapter](adapter.mdx) and the [MoveVM](adapter.mdx#move-vm). - The [Native Functions & Object Runtime](natives.mdx). -- The [IOTA Framework](../../references/framework.mdx). \ No newline at end of file +- The [IOTA Framework](../framework.mdx). \ No newline at end of file diff --git a/docs/content/about-iota/execution-architecture/iota-execution.mdx b/docs/content/references/execution-architecture/iota-execution.mdx similarity index 100% rename from docs/content/about-iota/execution-architecture/iota-execution.mdx rename to docs/content/references/execution-architecture/iota-execution.mdx diff --git a/docs/content/about-iota/execution-architecture/natives.mdx b/docs/content/references/execution-architecture/natives.mdx similarity index 100% rename from docs/content/about-iota/execution-architecture/natives.mdx rename to docs/content/references/execution-architecture/natives.mdx diff --git a/docs/content/references/iota-glossary.mdx b/docs/content/references/iota-glossary.mdx index 75929f62875..f39220836b4 100644 --- a/docs/content/references/iota-glossary.mdx +++ b/docs/content/references/iota-glossary.mdx @@ -75,11 +75,7 @@ A [smart contract](https://en.wikipedia.org/wiki/Smart_contract) is an agreement ### IOTA {#iota} -IOTA refers to the IOTA blockchain, and the [IOTA open source project](https://github.com/iotaledger/iota/) as a whole. - -### IOTA {#iota-1} - -IOTA is the native token to the IOTA network. +IOTA refers to the IOTA blockchain, and the [IOTA open source project](https://github.com/iotaledger/iota/) as a whole, or the native token to the IOTA network. ### Total order {#total-order} diff --git a/docs/content/sidebars/about-iota.js b/docs/content/sidebars/about-iota.js index 4f61f32d80c..f618bc0d3e9 100644 --- a/docs/content/sidebars/about-iota.js +++ b/docs/content/sidebars/about-iota.js @@ -39,24 +39,5 @@ const aboutIota = [ 'about-iota/tokenomics/gas-pricing', ], }, - { - type: 'category', - label: 'Expert topics', - items: [ - { - type: 'category', - label: 'Execution Architecture', - link: { - type: 'doc', - id: 'about-iota/execution-architecture/execution-layer', - }, - items: [ - 'about-iota/execution-architecture/iota-execution', - 'about-iota/execution-architecture/adapter', - 'about-iota/execution-architecture/natives', - ], - }, - ], - }, ]; module.exports = aboutIota; diff --git a/docs/content/sidebars/references.js b/docs/content/sidebars/references.js index fcac9fa935f..dd1d40015fd 100644 --- a/docs/content/sidebars/references.js +++ b/docs/content/sidebars/references.js @@ -323,6 +323,25 @@ const references = [ }, ], }, + { + type: 'category', + label: 'Expert topics', + items: [ + { + type: 'category', + label: 'Execution Architecture', + link: { + type: 'doc', + id: 'references/execution-architecture/execution-layer', + }, + items: [ + 'references/execution-architecture/iota-execution', + 'references/execution-architecture/adapter', + 'references/execution-architecture/natives', + ], + }, + ], + }, 'references/research-papers', 'references/iota-glossary', { @@ -334,13 +353,6 @@ const references = [ }, items: [ 'references/contribute/contribution-process', - 'references/contribute/contribute-to-iota-repos', - { - type: 'link', - label: 'Submit a SIP', - href: 'https://sips.iota.io', - }, - 'references/contribute/localize-iota-docs', 'references/contribute/code-of-conduct', 'references/contribute/style-guide', ], diff --git a/nre/validator_tool.md b/nre/validator_tool.md index ed512653a2e..cbeb008c435 100644 --- a/nre/validator_tool.md +++ b/nre/validator_tool.md @@ -169,6 +169,8 @@ At this point you are validator candidate and can start to accept self staking a **If you haven't, start a fullnode now to catch up with the network. When you officially join the committee but is not fully up-to-date, you cannot make meaningful contribution to the network and may be subject to peer reporting hence face the risk of reduced staking rewards for you and your delegators.** +Add stake to a validator's staking pool: https://docs.iota.org/references/framework/iota-system/iota_system#function-request_add_stake + Once you collect enough staking amount, run ```bash diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3dd5c2e8653..68b72efaa3b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1107,8 +1107,8 @@ importers: specifier: ^3.5.0 version: 3.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) next: - specifier: 14.2.3 - version: 14.2.3(@babel/core@7.23.9)(@playwright/test@1.46.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.63.6) + specifier: 14.2.10 + version: 14.2.10(@babel/core@7.23.9)(@playwright/test@1.46.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.63.6) react: specifier: ^18.3.1 version: 18.3.1 @@ -5254,62 +5254,62 @@ packages: '@nestjs/platform-express': optional: true - '@next/env@14.2.3': - resolution: {integrity: sha512-W7fd7IbkfmeeY2gXrzJYDx8D2lWKbVoTIj1o1ScPHNzvp30s1AuoEFSdr39bC5sjxJaxTtq3OTCZboNp0lNWHA==} + '@next/env@14.2.10': + resolution: {integrity: sha512-dZIu93Bf5LUtluBXIv4woQw2cZVZ2DJTjax5/5DOs3lzEOeKLy7GxRSr4caK9/SCPdaW6bCgpye6+n4Dh9oJPw==} '@next/eslint-plugin-next@14.2.3': resolution: {integrity: sha512-L3oDricIIjgj1AVnRdRor21gI7mShlSwU/1ZGHmqM3LzHhXXhdkrfeNY5zif25Bi5Dd7fiJHsbhoZCHfXYvlAw==} - '@next/swc-darwin-arm64@14.2.3': - resolution: {integrity: sha512-3pEYo/RaGqPP0YzwnlmPN2puaF2WMLM3apt5jLW2fFdXD9+pqcoTzRk+iZsf8ta7+quAe4Q6Ms0nR0SFGFdS1A==} + '@next/swc-darwin-arm64@14.2.10': + resolution: {integrity: sha512-V3z10NV+cvMAfxQUMhKgfQnPbjw+Ew3cnr64b0lr8MDiBJs3eLnM6RpGC46nhfMZsiXgQngCJKWGTC/yDcgrDQ==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@14.2.3': - resolution: {integrity: sha512-6adp7waE6P1TYFSXpY366xwsOnEXM+y1kgRpjSRVI2CBDOcbRjsJ67Z6EgKIqWIue52d2q/Mx8g9MszARj8IEA==} + '@next/swc-darwin-x64@14.2.10': + resolution: {integrity: sha512-Y0TC+FXbFUQ2MQgimJ/7Ina2mXIKhE7F+GUe1SgnzRmwFY3hX2z8nyVCxE82I2RicspdkZnSWMn4oTjIKz4uzA==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@14.2.3': - resolution: {integrity: sha512-cuzCE/1G0ZSnTAHJPUT1rPgQx1w5tzSX7POXSLaS7w2nIUJUD+e25QoXD/hMfxbsT9rslEXugWypJMILBj/QsA==} + '@next/swc-linux-arm64-gnu@14.2.10': + resolution: {integrity: sha512-ZfQ7yOy5zyskSj9rFpa0Yd7gkrBnJTkYVSya95hX3zeBG9E55Z6OTNPn1j2BTFWvOVVj65C3T+qsjOyVI9DQpA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-musl@14.2.3': - resolution: {integrity: sha512-0D4/oMM2Y9Ta3nGuCcQN8jjJjmDPYpHX9OJzqk42NZGJocU2MqhBq5tWkJrUQOQY9N+In9xOdymzapM09GeiZw==} + '@next/swc-linux-arm64-musl@14.2.10': + resolution: {integrity: sha512-n2i5o3y2jpBfXFRxDREr342BGIQCJbdAUi/K4q6Env3aSx8erM9VuKXHw5KNROK9ejFSPf0LhoSkU/ZiNdacpQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-x64-gnu@14.2.3': - resolution: {integrity: sha512-ENPiNnBNDInBLyUU5ii8PMQh+4XLr4pG51tOp6aJ9xqFQ2iRI6IH0Ds2yJkAzNV1CfyagcyzPfROMViS2wOZ9w==} + '@next/swc-linux-x64-gnu@14.2.10': + resolution: {integrity: sha512-GXvajAWh2woTT0GKEDlkVhFNxhJS/XdDmrVHrPOA83pLzlGPQnixqxD8u3bBB9oATBKB//5e4vpACnx5Vaxdqg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-linux-x64-musl@14.2.3': - resolution: {integrity: sha512-BTAbq0LnCbF5MtoM7I/9UeUu/8ZBY0i8SFjUMCbPDOLv+un67e2JgyN4pmgfXBwy/I+RHu8q+k+MCkDN6P9ViQ==} + '@next/swc-linux-x64-musl@14.2.10': + resolution: {integrity: sha512-opFFN5B0SnO+HTz4Wq4HaylXGFV+iHrVxd3YvREUX9K+xfc4ePbRrxqOuPOFjtSuiVouwe6uLeDtabjEIbkmDA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-win32-arm64-msvc@14.2.3': - resolution: {integrity: sha512-AEHIw/dhAMLNFJFJIJIyOFDzrzI5bAjI9J26gbO5xhAKHYTZ9Or04BesFPXiAYXDNdrwTP2dQceYA4dL1geu8A==} + '@next/swc-win32-arm64-msvc@14.2.10': + resolution: {integrity: sha512-9NUzZuR8WiXTvv+EiU/MXdcQ1XUvFixbLIMNQiVHuzs7ZIFrJDLJDaOF1KaqttoTujpcxljM/RNAOmw1GhPPQQ==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-ia32-msvc@14.2.3': - resolution: {integrity: sha512-vga40n1q6aYb0CLrM+eEmisfKCR45ixQYXuBXxOOmmoV8sYST9k7E3US32FsY+CkkF7NtzdcebiFT4CHuMSyZw==} + '@next/swc-win32-ia32-msvc@14.2.10': + resolution: {integrity: sha512-fr3aEbSd1GeW3YUMBkWAu4hcdjZ6g4NBl1uku4gAn661tcxd1bHs1THWYzdsbTRLcCKLjrDZlNp6j2HTfrw+Bg==} engines: {node: '>= 10'} cpu: [ia32] os: [win32] - '@next/swc-win32-x64-msvc@14.2.3': - resolution: {integrity: sha512-Q1/zm43RWynxrO7lW4ehciQVj+5ePBhOK+/K2P7pLFX3JaJ/IZVC69SHidrmZSOkqz7ECIOhhy7XhAFG4JYyHA==} + '@next/swc-win32-x64-msvc@14.2.10': + resolution: {integrity: sha512-UjeVoRGKNL2zfbcQ6fscmgjBAS/inHBh63mjIlfPg/NG8Yn2ztqylXt5qilYb6hoHIwaU2ogHknHWWmahJjgZQ==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -8975,9 +8975,6 @@ packages: caniuse-lite@1.0.30001520: resolution: {integrity: sha512-tahF5O9EiiTzwTUqAeFjIZbn4Dnqxzz7ktrgGlMYNLH43Ul26IgTMH/zvL3DG0lZxBYnlT04axvInszUsZULdA==} - caniuse-lite@1.0.30001585: - resolution: {integrity: sha512-yr2BWR1yLXQ8fMpdS/4ZZXpseBgE7o4g41x3a6AJOqZuOi+iE/WdJYAuZ6Y95i4Ohd2Y+9MzIWRR+uGABH4s3Q==} - caniuse-lite@1.0.30001636: resolution: {integrity: sha512-bMg2vmr8XBsbL6Lr0UHXy/21m84FTxDLWn2FSqMd5PrlbMxwJlQnC2YWYxVgp66PZE+BBNF2jYQUBKCo1FDeZg==} @@ -13461,8 +13458,8 @@ packages: neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - next@14.2.3: - resolution: {integrity: sha512-dowFkFTR8v79NPJO4QsBUtxv0g9BrS/phluVpMAt2ku7H+cbcBJlopXjkWlwxrk/xGqMemr7JkGPGemPrLLX7A==} + next@14.2.10: + resolution: {integrity: sha512-sDDExXnh33cY3RkS9JuFEKaS4HmlWmDKP1VJioucCG6z5KuA008DPsDZOzi8UfqEk3Ii+2NCQSJrfbEWtZZfww==} engines: {node: '>=18.17.0'} hasBin: true peerDependencies: @@ -22898,37 +22895,37 @@ snapshots: optionalDependencies: '@nestjs/platform-express': 10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8) - '@next/env@14.2.3': {} + '@next/env@14.2.10': {} '@next/eslint-plugin-next@14.2.3': dependencies: glob: 10.3.10 - '@next/swc-darwin-arm64@14.2.3': + '@next/swc-darwin-arm64@14.2.10': optional: true - '@next/swc-darwin-x64@14.2.3': + '@next/swc-darwin-x64@14.2.10': optional: true - '@next/swc-linux-arm64-gnu@14.2.3': + '@next/swc-linux-arm64-gnu@14.2.10': optional: true - '@next/swc-linux-arm64-musl@14.2.3': + '@next/swc-linux-arm64-musl@14.2.10': optional: true - '@next/swc-linux-x64-gnu@14.2.3': + '@next/swc-linux-x64-gnu@14.2.10': optional: true - '@next/swc-linux-x64-musl@14.2.3': + '@next/swc-linux-x64-musl@14.2.10': optional: true - '@next/swc-win32-arm64-msvc@14.2.3': + '@next/swc-win32-arm64-msvc@14.2.10': optional: true - '@next/swc-win32-ia32-msvc@14.2.3': + '@next/swc-win32-ia32-msvc@14.2.10': optional: true - '@next/swc-win32-x64-msvc@14.2.3': + '@next/swc-win32-x64-msvc@14.2.10': optional: true '@nicolo-ribaudo/semver-v6@6.3.3': {} @@ -28140,8 +28137,6 @@ snapshots: caniuse-lite@1.0.30001520: {} - caniuse-lite@1.0.30001585: {} - caniuse-lite@1.0.30001636: {} capital-case@1.0.4: @@ -34367,27 +34362,27 @@ snapshots: neo-async@2.6.2: {} - next@14.2.3(@babel/core@7.23.9)(@playwright/test@1.46.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.63.6): + next@14.2.10(@babel/core@7.23.9)(@playwright/test@1.46.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.63.6): dependencies: - '@next/env': 14.2.3 + '@next/env': 14.2.10 '@swc/helpers': 0.5.5 busboy: 1.6.0 - caniuse-lite: 1.0.30001585 + caniuse-lite: 1.0.30001636 graceful-fs: 4.2.11 postcss: 8.4.31 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) styled-jsx: 5.1.1(@babel/core@7.23.9)(babel-plugin-macros@3.1.0)(react@18.3.1) optionalDependencies: - '@next/swc-darwin-arm64': 14.2.3 - '@next/swc-darwin-x64': 14.2.3 - '@next/swc-linux-arm64-gnu': 14.2.3 - '@next/swc-linux-arm64-musl': 14.2.3 - '@next/swc-linux-x64-gnu': 14.2.3 - '@next/swc-linux-x64-musl': 14.2.3 - '@next/swc-win32-arm64-msvc': 14.2.3 - '@next/swc-win32-ia32-msvc': 14.2.3 - '@next/swc-win32-x64-msvc': 14.2.3 + '@next/swc-darwin-arm64': 14.2.10 + '@next/swc-darwin-x64': 14.2.10 + '@next/swc-linux-arm64-gnu': 14.2.10 + '@next/swc-linux-arm64-musl': 14.2.10 + '@next/swc-linux-x64-gnu': 14.2.10 + '@next/swc-linux-x64-musl': 14.2.10 + '@next/swc-win32-arm64-msvc': 14.2.10 + '@next/swc-win32-ia32-msvc': 14.2.10 + '@next/swc-win32-x64-msvc': 14.2.10 '@playwright/test': 1.46.1 sass: 1.63.6 transitivePeerDependencies: