diff --git a/configs/app/features/faultProofSystem.ts b/configs/app/features/faultProofSystem.ts new file mode 100644 index 0000000000..38a8f021db --- /dev/null +++ b/configs/app/features/faultProofSystem.ts @@ -0,0 +1,22 @@ +import type { Feature } from './types'; + +import { getEnvValue } from '../utils'; +import rollup from './rollup'; + +const title = 'Fault proof system'; + +const config: Feature<{ isEnabled: true }> = (() => { + if (rollup.isEnabled && rollup.type === 'optimistic' && getEnvValue('NEXT_PUBLIC_FAULT_PROOF_ENABLED') === 'true') { + return Object.freeze({ + title, + isEnabled: true, + }); + } + + return Object.freeze({ + title, + isEnabled: false, + }); +})(); + +export default config; diff --git a/configs/app/features/index.ts b/configs/app/features/index.ts index 312c38daa0..79e0051141 100644 --- a/configs/app/features/index.ts +++ b/configs/app/features/index.ts @@ -8,6 +8,7 @@ export { default as bridgedTokens } from './bridgedTokens'; export { default as blockchainInteraction } from './blockchainInteraction'; export { default as csvExport } from './csvExport'; export { default as dataAvailability } from './dataAvailability'; +export { default as faultProofSystem } from './faultProofSystem'; export { default as gasTracker } from './gasTracker'; export { default as googleAnalytics } from './googleAnalytics'; export { default as graphqlApiDocs } from './graphqlApiDocs'; diff --git a/configs/envs/.env.optimism_sepolia b/configs/envs/.env.optimism_sepolia index 7bf13dc4a1..e60e578a36 100644 --- a/configs/envs/.env.optimism_sepolia +++ b/configs/envs/.env.optimism_sepolia @@ -61,3 +61,4 @@ NEXT_PUBLIC_VIEWS_CONTRACT_SOLIDITYSCAN_ENABLED=true NEXT_PUBLIC_ROLLUP_TYPE=optimistic NEXT_PUBLIC_ROLLUP_L2_WITHDRAWAL_URL=https://app.optimism.io/bridge/withdraw NEXT_PUBLIC_ROLLUP_L1_BASE_URL=https://eth-sepolia.blockscout.com/ +NEXT_PUBLIC_FAULT_PROOF_ENABLED=true diff --git a/deploy/tools/envs-validator/schema.ts b/deploy/tools/envs-validator/schema.ts index 9f3c7f27e1..8de1031fb7 100644 --- a/deploy/tools/envs-validator/schema.ts +++ b/deploy/tools/envs-validator/schema.ts @@ -629,6 +629,16 @@ const schema = yup NEXT_PUBLIC_GAS_TRACKER_ENABLED: yup.boolean(), NEXT_PUBLIC_GAS_TRACKER_UNITS: yup.array().transform(replaceQuotes).json().of(yup.string().oneOf(GAS_UNITS)), NEXT_PUBLIC_DATA_AVAILABILITY_ENABLED: yup.boolean(), + NEXT_PUBLIC_FAULT_PROOF_ENABLED: yup.boolean() + .when('NEXT_PUBLIC_ROLLUP_TYPE', { + is: 'optimistic', + then: (schema) => schema, + otherwise: (schema) => schema.test( + 'not-exist', + 'NEXT_PUBLIC_FAULT_PROOF_ENABLED can only be used with NEXT_PUBLIC_ROLLUP_TYPE=optimistic', + value => value === undefined, + ), + }), // 6. External services envs NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID: yup.string(), diff --git a/deploy/tools/envs-validator/test/.env.rollup b/deploy/tools/envs-validator/test/.env.rollup index 1cb3e1af88..e7cacfb086 100644 --- a/deploy/tools/envs-validator/test/.env.rollup +++ b/deploy/tools/envs-validator/test/.env.rollup @@ -1,3 +1,4 @@ NEXT_PUBLIC_ROLLUP_TYPE=optimistic NEXT_PUBLIC_ROLLUP_L1_BASE_URL=https://example.com -NEXT_PUBLIC_ROLLUP_L2_WITHDRAWAL_URL=https://example.com \ No newline at end of file +NEXT_PUBLIC_ROLLUP_L2_WITHDRAWAL_URL=https://example.com +NEXT_PUBLIC_FAULT_PROOF_ENABLED=true \ No newline at end of file diff --git a/docs/ENVS.md b/docs/ENVS.md index 7e2a8bd211..1f5eb1784d 100644 --- a/docs/ENVS.md +++ b/docs/ENVS.md @@ -36,6 +36,7 @@ Please be aware that all environment variables prefixed with `NEXT_PUBLIC_` will - [Beacon chain](ENVS.md#beacon-chain) - [User operations](ENVS.md#user-operations-feature-erc-4337) - [Rollup chain](ENVS.md#rollup-chain) + - [Fault proof system](ENVS.md#fault-proof-system) - [Export data to CSV file](ENVS.md#export-data-to-csv-file) - [Google analytics](ENVS.md#google-analytics) - [Mixpanel analytics](ENVS.md#mixpanel-analytics) @@ -401,6 +402,14 @@ This feature is **enabled by default** with the `coinzilla` ads provider. To swi   +### Fault proof system + +| Variable | Type| Description | Compulsoriness | Default value | Example value | +| --- | --- | --- | --- | --- | --- | +| NEXT_PUBLIC_FAULT_PROOF_ENABLED | `boolean` | Set to `true` for chains with fault proof system enabled (OP stack only) | - | - | `true` | + +  + ### Export data to CSV file | Variable | Type| Description | Compulsoriness | Default value | Example value | diff --git a/lib/api/resources.ts b/lib/api/resources.ts index 53f864238d..26686f287c 100644 --- a/lib/api/resources.ts +++ b/lib/api/resources.ts @@ -64,6 +64,7 @@ import type { OptimisticL2OutputRootsResponse, OptimisticL2TxnBatchesResponse, OptimisticL2WithdrawalsResponse, + OptimisticL2DisputeGamesResponse, } from 'types/api/optimisticL2'; import type { RawTracesResponse } from 'types/api/rawTrace'; import type { SearchRedirectResult, SearchResult, SearchResultFilters, SearchResultItem } from 'types/api/search'; @@ -650,6 +651,15 @@ export const RESOURCES = { path: '/api/v2/optimism/txn-batches/count', }, + optimistic_l2_dispute_games: { + path: '/api/v2/optimism/games', + filterFields: [], + }, + + optimistic_l2_dispute_games_count: { + path: '/api/v2/optimism/games/count', + }, + // zkEvm L2 zkevm_l2_deposits: { path: '/api/v2/zkevm/deposits', @@ -853,6 +863,7 @@ export type PaginatedResources = 'blocks' | 'block_txs' | 'token_instance_transfers' | 'token_instance_holders' | 'verified_contracts' | 'optimistic_l2_output_roots' | 'optimistic_l2_withdrawals' | 'optimistic_l2_txn_batches' | 'optimistic_l2_deposits' | +'optimistic_l2_dispute_games' | 'shibarium_deposits' | 'shibarium_withdrawals' | 'zkevm_l2_deposits' | 'zkevm_l2_withdrawals' | 'zkevm_l2_txn_batches' | 'zkevm_l2_txn_batch_txs' | 'zksync_l2_txn_batches' | 'zksync_l2_txn_batch_txs' | @@ -955,13 +966,12 @@ Q extends 'optimistic_l2_output_roots' ? OptimisticL2OutputRootsResponse : Q extends 'optimistic_l2_withdrawals' ? OptimisticL2WithdrawalsResponse : Q extends 'optimistic_l2_deposits' ? OptimisticL2DepositsResponse : Q extends 'optimistic_l2_txn_batches' ? OptimisticL2TxnBatchesResponse : +Q extends 'optimistic_l2_dispute_games' ? OptimisticL2DisputeGamesResponse : Q extends 'optimistic_l2_output_roots_count' ? number : Q extends 'optimistic_l2_withdrawals_count' ? number : Q extends 'optimistic_l2_deposits_count' ? number : Q extends 'optimistic_l2_txn_batches_count' ? number : -Q extends 'config_backend_version' ? BackendVersionConfig : -Q extends 'address_metadata_info' ? AddressMetadataInfo : -Q extends 'address_metadata_tag_types' ? PublicTagTypesResponse : +Q extends 'optimistic_l2_dispute_games_count' ? number : never; // !!! IMPORTANT !!! // See comment above @@ -969,6 +979,9 @@ never; /* eslint-disable @typescript-eslint/indent */ export type ResourcePayloadB = +Q extends 'config_backend_version' ? BackendVersionConfig : +Q extends 'address_metadata_info' ? AddressMetadataInfo : +Q extends 'address_metadata_tag_types' ? PublicTagTypesResponse : Q extends 'blob' ? Blob : Q extends 'marketplace_dapps' ? Array : Q extends 'marketplace_dapp' ? MarketplaceAppOverview : diff --git a/lib/hooks/useNavItems.tsx b/lib/hooks/useNavItems.tsx index 976b19f361..a2d2732b2c 100644 --- a/lib/hooks/useNavItems.tsx +++ b/lib/hooks/useNavItems.tsx @@ -96,6 +96,12 @@ export default function useNavItems(): ReturnType { icon: 'output_roots', isActive: pathname === '/output-roots', }; + const rollupDisputeGames = config.features.faultProofSystem.isEnabled ? { + text: 'Dispute games', + nextRoute: { pathname: '/dispute-games' as const }, + icon: 'output_roots', + isActive: pathname === '/dispute-games', + } : null; const rollupFeature = config.features.rollup; @@ -109,6 +115,7 @@ export default function useNavItems(): ReturnType { [ blocks, rollupTxnBatches, + rollupDisputeGames, rollupFeature.type === 'optimistic' ? rollupOutputRoots : undefined, ].filter(Boolean), [ diff --git a/lib/metadata/getPageOgType.ts b/lib/metadata/getPageOgType.ts index d26f4a5814..66319f429e 100644 --- a/lib/metadata/getPageOgType.ts +++ b/lib/metadata/getPageOgType.ts @@ -35,6 +35,7 @@ const OG_TYPE_DICT: Record = { '/csv-export': 'Regular page', '/deposits': 'Root page', '/output-roots': 'Root page', + '/dispute-games': 'Root page', '/batches': 'Root page', '/batches/[number]': 'Regular page', '/blobs/[hash]': 'Regular page', diff --git a/lib/metadata/templates/description.ts b/lib/metadata/templates/description.ts index 80a996eba7..08acaaf1c8 100644 --- a/lib/metadata/templates/description.ts +++ b/lib/metadata/templates/description.ts @@ -39,6 +39,7 @@ const TEMPLATE_MAP: Record = { '/csv-export': DEFAULT_TEMPLATE, '/deposits': DEFAULT_TEMPLATE, '/output-roots': DEFAULT_TEMPLATE, + '/dispute-games': DEFAULT_TEMPLATE, '/batches': DEFAULT_TEMPLATE, '/batches/[number]': DEFAULT_TEMPLATE, '/blobs/[hash]': DEFAULT_TEMPLATE, diff --git a/lib/metadata/templates/title.ts b/lib/metadata/templates/title.ts index 2c02f03d0f..a28c559686 100644 --- a/lib/metadata/templates/title.ts +++ b/lib/metadata/templates/title.ts @@ -33,6 +33,7 @@ const TEMPLATE_MAP: Record = { '/csv-export': 'export data to CSV', '/deposits': 'deposits (L1 > L2)', '/output-roots': 'output roots', + '/dispute-games': 'dispute games', '/batches': 'tx batches (L2 blocks)', '/batches/[number]': 'L2 tx batch %number%', '/blobs/[hash]': 'blob %hash% details', diff --git a/lib/mixpanel/getPageType.ts b/lib/mixpanel/getPageType.ts index e47872ab43..e53554756b 100644 --- a/lib/mixpanel/getPageType.ts +++ b/lib/mixpanel/getPageType.ts @@ -33,6 +33,7 @@ export const PAGE_TYPE_DICT: Record = { '/csv-export': 'Export data to CSV file', '/deposits': 'Deposits (L1 > L2)', '/output-roots': 'Output roots', + '/dispute-games': 'Dispute games', '/batches': 'Tx batches (L2 blocks)', '/batches/[number]': 'L2 tx batch details', '/blobs/[hash]': 'Blob details', diff --git a/nextjs/getServerSideProps.ts b/nextjs/getServerSideProps.ts index 7a00e59340..844c7ddd35 100644 --- a/nextjs/getServerSideProps.ts +++ b/nextjs/getServerSideProps.ts @@ -251,3 +251,13 @@ export const publicTagsSubmit: GetServerSideProps = async(context) => { return base(context); }; + +export const disputeGames: GetServerSideProps = async(context) => { + if (!config.features.faultProofSystem.isEnabled) { + return { + notFound: true, + }; + } + + return base(context); +}; diff --git a/nextjs/nextjs-routes.d.ts b/nextjs/nextjs-routes.d.ts index 07337c1b06..c8a72eeae1 100644 --- a/nextjs/nextjs-routes.d.ts +++ b/nextjs/nextjs-routes.d.ts @@ -35,6 +35,7 @@ declare module "nextjs-routes" { | StaticRoute<"/contract-verification"> | StaticRoute<"/csv-export"> | StaticRoute<"/deposits"> + | StaticRoute<"/dispute-games"> | StaticRoute<"/gas-tracker"> | StaticRoute<"/graphiql"> | StaticRoute<"/"> diff --git a/pages/dispute-games/index.tsx b/pages/dispute-games/index.tsx new file mode 100644 index 0000000000..fd4c983cc3 --- /dev/null +++ b/pages/dispute-games/index.tsx @@ -0,0 +1,19 @@ +import type { NextPage } from 'next'; +import dynamic from 'next/dynamic'; +import React from 'react'; + +import PageNextJs from 'nextjs/PageNextJs'; + +const DisputeGames = dynamic(() => import('ui/pages/OptimisticL2DisputeGames'), { ssr: false }); + +const Page: NextPage = () => { + return ( + + + + ); +}; + +export default Page; + +export { disputeGames as getServerSideProps } from 'nextjs/getServerSideProps'; diff --git a/stubs/L2.ts b/stubs/L2.ts index 21346e0ef5..20bb128d90 100644 --- a/stubs/L2.ts +++ b/stubs/L2.ts @@ -1,5 +1,6 @@ import type { OptimisticL2DepositsItem, + OptimisticL2DisputeGamesItem, OptimisticL2OutputRootsItem, OptimisticL2TxnBatchesItem, OptimisticL2WithdrawalsItem, @@ -45,3 +46,13 @@ export const L2_OUTPUT_ROOTS_ITEM: OptimisticL2OutputRootsItem = { l2_output_index: 50655, output_root: TX_HASH, }; + +export const L2_DISPUTE_GAMES_ITEM: OptimisticL2DisputeGamesItem = { + contract_address: ADDRESS_HASH, + created_at: '2023-06-01T15:26:12.000000Z', + game_type: 0, + index: 6594, + l2_block_number: 50655, + resolved_at: null, + status: 'In progress', +}; diff --git a/types/api/optimisticL2.ts b/types/api/optimisticL2.ts index 0d9496d69c..3940715533 100644 --- a/types/api/optimisticL2.ts +++ b/types/api/optimisticL2.ts @@ -61,15 +61,15 @@ export type OptimisticL2WithdrawalsItem = { 'status': string; } -export const WITHDRAWAL_STATUSES = [ - 'Waiting for state root', - 'Ready to prove', - 'In challenge period', - 'Ready for relay', - 'Relayed', -] as const; - -export type OptimisticL2WithdrawalStatus = typeof WITHDRAWAL_STATUSES[number]; +export type OptimisticL2WithdrawalStatus = + 'Waiting for state root' | + 'Ready to prove' | + 'In challenge period' | + 'Waiting a game to resolve' | + 'Ready to prove' | + 'Proven' | + 'Ready for relay' | + 'Relayed'; export type OptimisticL2WithdrawalsResponse = { items: Array; @@ -78,3 +78,21 @@ export type OptimisticL2WithdrawalsResponse = { 'nonce': string; }; } + +export type OptimisticL2DisputeGamesResponse = { + items: Array; + 'next_page_params': { + 'items_count': number; + 'index': number; + }; +} + +export type OptimisticL2DisputeGamesItem = { + contract_address: string; + created_at: string; + game_type: number; + index: number; + l2_block_number: number; + resolved_at: string | null; + status: string; +} diff --git a/ui/disputeGames/optimisticL2/OptimisticL2DisputeGamesListItem.tsx b/ui/disputeGames/optimisticL2/OptimisticL2DisputeGamesListItem.tsx new file mode 100644 index 0000000000..3c6546de3b --- /dev/null +++ b/ui/disputeGames/optimisticL2/OptimisticL2DisputeGamesListItem.tsx @@ -0,0 +1,76 @@ +import { Skeleton } from '@chakra-ui/react'; +import React from 'react'; + +import type { OptimisticL2DisputeGamesItem } from 'types/api/optimisticL2'; + +import config from 'configs/app'; +import dayjs from 'lib/date/dayjs'; +import CopyToClipboard from 'ui/shared/CopyToClipboard'; +import BlockEntityL2 from 'ui/shared/entities/block/BlockEntityL2'; +import HashStringShorten from 'ui/shared/HashStringShorten'; +import ListItemMobileGrid from 'ui/shared/ListItemMobile/ListItemMobileGrid'; + +const rollupFeature = config.features.rollup; + +type Props = { item: OptimisticL2DisputeGamesItem; isLoading?: boolean }; + +const OptimisticL2DisputeGamesListItem = ({ item, isLoading }: Props) => { + if (!rollupFeature.isEnabled || rollupFeature.type !== 'optimistic') { + return null; + } + + return ( + + + Index + + { item.index } + + + Game type + + { item.game_type } + + + Address + + + + + + + + L2 block # + + + + + Age + + { dayjs(item.created_at).fromNow() } + + + Status + + { item.status } + + + { item.resolved_at && ( + <> + Resolution age + { dayjs(item.resolved_at).fromNow() } + + + ) } + + + ); +}; + +export default OptimisticL2DisputeGamesListItem; diff --git a/ui/disputeGames/optimisticL2/OptimisticL2DisputeGamesTable.tsx b/ui/disputeGames/optimisticL2/OptimisticL2DisputeGamesTable.tsx new file mode 100644 index 0000000000..79179c6109 --- /dev/null +++ b/ui/disputeGames/optimisticL2/OptimisticL2DisputeGamesTable.tsx @@ -0,0 +1,43 @@ +import { Table, Tbody, Th, Tr } from '@chakra-ui/react'; +import React from 'react'; + +import type { OptimisticL2DisputeGamesItem } from 'types/api/optimisticL2'; + +import { default as Thead } from 'ui/shared/TheadSticky'; + +import OptimisticL2DisputeGamesTableItem from './OptimisticL2DisputeGamesTableItem'; + +type Props = { + items: Array; + top: number; + isLoading?: boolean; +} + +const OptimisticL2DisputeGamesTable = ({ items, top, isLoading }: Props) => { + return ( + + + + + + + + + + + + + + { items.map((item, index) => ( + + )) } + +
IndexGame typeAddressL2 block #AgeStatusResolution age
+ ); +}; + +export default OptimisticL2DisputeGamesTable; diff --git a/ui/disputeGames/optimisticL2/OptimisticL2DisputeGamesTableItem.tsx b/ui/disputeGames/optimisticL2/OptimisticL2DisputeGamesTableItem.tsx new file mode 100644 index 0000000000..0de2ced695 --- /dev/null +++ b/ui/disputeGames/optimisticL2/OptimisticL2DisputeGamesTableItem.tsx @@ -0,0 +1,61 @@ +import { Flex, Td, Tr, Skeleton } from '@chakra-ui/react'; +import React from 'react'; + +import type { OptimisticL2DisputeGamesItem } from 'types/api/optimisticL2'; + +import config from 'configs/app'; +import dayjs from 'lib/date/dayjs'; +import CopyToClipboard from 'ui/shared/CopyToClipboard'; +import BlockEntityL2 from 'ui/shared/entities/block/BlockEntityL2'; +import HashStringShorten from 'ui/shared/HashStringShorten'; + +const faultProofSystemFeature = config.features.faultProofSystem; + +type Props = { item: OptimisticL2DisputeGamesItem; isLoading?: boolean }; + +const OptimisticL2DisputeGamesTableItem = ({ item, isLoading }: Props) => { + if (!faultProofSystemFeature.isEnabled) { + return null; + } + + return ( + + + { item.index } + + + { item.game_type } + + + + + + + + + + + + + + { dayjs(item.created_at).fromNow() } + + + { item.status } + + + + { item.resolved_at ? dayjs(item.resolved_at).fromNow() : 'N/A' } + + + + ); +}; + +export default OptimisticL2DisputeGamesTableItem; diff --git a/ui/pages/OptimisticL2DisputeGames.tsx b/ui/pages/OptimisticL2DisputeGames.tsx new file mode 100644 index 0000000000..a21f5061e4 --- /dev/null +++ b/ui/pages/OptimisticL2DisputeGames.tsx @@ -0,0 +1,86 @@ +import { Hide, Show, Skeleton, Text } from '@chakra-ui/react'; +import React from 'react'; + +import useApiQuery from 'lib/api/useApiQuery'; +import { L2_DISPUTE_GAMES_ITEM } from 'stubs/L2'; +import { generateListStub } from 'stubs/utils'; +import OptimisticL2DisputeGamesListItem from 'ui/disputeGames/optimisticL2/OptimisticL2DisputeGamesListItem'; +import OptimisticL2DisputeGamesTable from 'ui/disputeGames/optimisticL2/OptimisticL2DisputeGamesTable'; +import { ACTION_BAR_HEIGHT_DESKTOP } from 'ui/shared/ActionBar'; +import DataListDisplay from 'ui/shared/DataListDisplay'; +import PageTitle from 'ui/shared/Page/PageTitle'; +import useQueryWithPages from 'ui/shared/pagination/useQueryWithPages'; +import StickyPaginationWithText from 'ui/shared/StickyPaginationWithText'; + +const OptimisticL2DisputeGames = () => { + const { data, isError, isPlaceholderData, pagination } = useQueryWithPages({ + resourceName: 'optimistic_l2_dispute_games', + options: { + placeholderData: generateListStub<'optimistic_l2_dispute_games'>( + L2_DISPUTE_GAMES_ITEM, + 50, + { + next_page_params: { + items_count: 50, + index: 9045200, + }, + }, + ), + }, + }); + + const countersQuery = useApiQuery('optimistic_l2_dispute_games_count', { + queryOptions: { + placeholderData: 50617, + }, + }); + + const content = data?.items ? ( + <> + + { data.items.map(((item, index) => ( + + ))) } + + + + + + ) : null; + + const text = (() => { + if (countersQuery.isError || isError || !data?.items.length) { + return null; + } + + return ( + + Dispute game index + #{ data.items[0].index } to + #{ data.items[data.items.length - 1].index } + (total of { countersQuery.data?.toLocaleString() } games) + + ); + })(); + + const actionBar = ; + + return ( + <> + + + + ); +}; + +export default OptimisticL2DisputeGames; diff --git a/ui/tx/details/TxDetailsWithdrawalStatus.tsx b/ui/tx/details/TxDetailsWithdrawalStatus.tsx index a1b4af7d8a..6e30e5a163 100644 --- a/ui/tx/details/TxDetailsWithdrawalStatus.tsx +++ b/ui/tx/details/TxDetailsWithdrawalStatus.tsx @@ -2,7 +2,6 @@ import { Button } from '@chakra-ui/react'; import React from 'react'; import type { OptimisticL2WithdrawalStatus } from 'types/api/optimisticL2'; -import { WITHDRAWAL_STATUSES } from 'types/api/optimisticL2'; import config from 'configs/app'; import TxEntityL1 from 'ui/shared/entities/tx/TxEntityL1'; @@ -13,10 +12,34 @@ interface Props { l1TxHash: string | undefined; } +const WITHDRAWAL_STATUS_STEPS: Array = [ + 'Waiting for state root', + 'Ready to prove', + 'In challenge period', + 'Ready for relay', + 'Relayed', +]; + +const WITHDRAWAL_STATUS_ORDER_PROVEN: Array = [ + 'Waiting for state root', + 'Ready to prove', + 'Proven', + 'Relayed', +]; + +const WITHDRAWAL_STATUS_ORDER_GAME: Array = [ + 'Waiting for state root', + 'Ready to prove', + 'Waiting a game to resolve', + 'In challenge period', + 'Ready for relay', + 'Relayed', +]; + const rollupFeature = config.features.rollup; const TxDetailsWithdrawalStatus = ({ status, l1TxHash }: Props) => { - if (!status || !WITHDRAWAL_STATUSES.includes(status) || !rollupFeature.isEnabled || rollupFeature.type !== 'optimistic') { + if (!status || !rollupFeature.isEnabled || rollupFeature.type !== 'optimistic') { return null; } @@ -25,10 +48,14 @@ const TxDetailsWithdrawalStatus = ({ status, l1TxHash }: Props) => { const steps = (() => { switch (status) { case 'Ready for relay': - return WITHDRAWAL_STATUSES.slice(0, -1); + return WITHDRAWAL_STATUS_STEPS.slice(0, -1); + case 'Proven': + return WITHDRAWAL_STATUS_ORDER_PROVEN; + case 'Waiting a game to resolve': + return WITHDRAWAL_STATUS_ORDER_GAME; case 'Relayed': { if (l1TxHash) { - return WITHDRAWAL_STATUSES.map((status) => { + return WITHDRAWAL_STATUS_STEPS.map((status) => { return status === 'Relayed' ? { content: , label: status, @@ -36,11 +63,11 @@ const TxDetailsWithdrawalStatus = ({ status, l1TxHash }: Props) => { }); } - return WITHDRAWAL_STATUSES; + return WITHDRAWAL_STATUS_STEPS; } default: - return WITHDRAWAL_STATUSES; + return WITHDRAWAL_STATUS_STEPS; } })();