From 2ffc1e5702001854a760010daacddc8989177814 Mon Sep 17 00:00:00 2001 From: tom goriunov Date: Mon, 9 Oct 2023 15:41:52 -0300 Subject: [PATCH] Suave customization (#1256) * new fields in tx details page * execution node txs page * tab for wrapped tx details * add loading state to tabs * types enhancement * change review env api host * add front app paths to review env * rename fields * [skip ci] execution node -> computor * rollback envs for review stand * add ENV for SUAVE --- configs/app/features/index.ts | 1 + configs/app/features/suave.ts | 21 ++++ deploy/tools/envs-validator/schema.ts | 1 + deploy/values/review/values.yaml.gotmpl | 2 + docs/ENVS.md | 11 ++ lib/api/resources.ts | 8 +- lib/metadata/getPageOgType.ts | 1 + lib/metadata/templates/description.ts | 1 + lib/metadata/templates/title.ts | 1 + lib/mixpanel/getPageType.ts | 1 + nextjs/getServerSideProps.ts | 10 ++ nextjs/nextjs-routes.d.ts | 1 + pages/txs/computor/[hash].tsx | 20 ++++ pages/{txs.tsx => txs/index.tsx} | 0 types/api/transaction.ts | 7 ++ types/utils.ts | 2 + ui/block/BlockDetails.tsx | 14 +-- ui/pages/ComputorTxs.tsx | 42 +++++++ ui/pages/Transaction.tsx | 34 ++++-- .../DetailsInfoItemDivider.tsx} | 4 +- ui/tokenInstance/TokenInstanceDetails.tsx | 4 +- .../details/TokenInstanceMetadataInfo.tsx | 5 +- ui/tx/TxAllowedPeekers.tsx | 41 +++++++ ui/tx/TxDetails.tsx | 90 +++++---------- ui/tx/TxDetailsWrapped.tsx | 109 ++++++++++++++++++ ui/tx/details/TxDetailsGasPrice.tsx | 31 +++++ ui/tx/details/TxDetailsOther.tsx | 49 ++++++++ 27 files changed, 423 insertions(+), 88 deletions(-) create mode 100644 configs/app/features/suave.ts create mode 100644 pages/txs/computor/[hash].tsx rename pages/{txs.tsx => txs/index.tsx} (100%) create mode 100644 ui/pages/ComputorTxs.tsx rename ui/{tokenInstance/details/TokenInstanceDivider.tsx => shared/DetailsInfoItemDivider.tsx} (77%) create mode 100644 ui/tx/TxAllowedPeekers.tsx create mode 100644 ui/tx/TxDetailsWrapped.tsx create mode 100644 ui/tx/details/TxDetailsGasPrice.tsx create mode 100644 ui/tx/details/TxDetailsOther.tsx diff --git a/configs/app/features/index.ts b/configs/app/features/index.ts index 1cc86a0d73..eba8a1cf56 100644 --- a/configs/app/features/index.ts +++ b/configs/app/features/index.ts @@ -15,5 +15,6 @@ export { default as safe } from './safe'; export { default as sentry } from './sentry'; export { default as sol2uml } from './sol2uml'; export { default as stats } from './stats'; +export { default as suave } from './suave'; export { default as web3Wallet } from './web3Wallet'; export { default as verifiedTokens } from './verifiedTokens'; diff --git a/configs/app/features/suave.ts b/configs/app/features/suave.ts new file mode 100644 index 0000000000..f96b80ede4 --- /dev/null +++ b/configs/app/features/suave.ts @@ -0,0 +1,21 @@ +import type { Feature } from './types'; + +import { getEnvValue } from '../utils'; + +const title = 'SUAVE chain'; + +const config: Feature<{ isEnabled: true }> = (() => { + if (getEnvValue('NEXT_PUBLIC_IS_SUAVE_CHAIN') === 'true') { + return Object.freeze({ + title, + isEnabled: true, + }); + } + + return Object.freeze({ + title, + isEnabled: false, + }); +})(); + +export default config; diff --git a/deploy/tools/envs-validator/schema.ts b/deploy/tools/envs-validator/schema.ts index 031e4d8699..47d3ad60df 100644 --- a/deploy/tools/envs-validator/schema.ts +++ b/deploy/tools/envs-validator/schema.ts @@ -357,6 +357,7 @@ const schema = yup NEXT_PUBLIC_PROMOTE_BLOCKSCOUT_IN_TITLE: yup.boolean(), NEXT_PUBLIC_OG_DESCRIPTION: yup.string(), NEXT_PUBLIC_OG_IMAGE_URL: yup.string().test(urlTest), + NEXT_PUBLIC_IS_SUAVE_CHAIN: yup.boolean(), // 6. External services envs NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID: yup.string(), diff --git a/deploy/values/review/values.yaml.gotmpl b/deploy/values/review/values.yaml.gotmpl index d6b931bee0..591686dc9a 100644 --- a/deploy/values/review/values.yaml.gotmpl +++ b/deploy/values/review/values.yaml.gotmpl @@ -17,12 +17,14 @@ frontend: exact: # - "/(apps|auth/profile|account)" - "/" + - "/envs.js" prefix: - "/_next" - "/node-api" - "/account" - "/apps" - "/static" + - "/assets" - "/favicon" - "/auth/profile" - "/auth/unverified-email" diff --git a/docs/ENVS.md b/docs/ENVS.md index fc3d376860..52175ac070 100644 --- a/docs/ENVS.md +++ b/docs/ENVS.md @@ -35,6 +35,7 @@ The app instance could be customized by passing following variables to NodeJS en - [Blockchain statistics](ENVS.md#blockchain-statistics) - [Web3 wallet integration](ENVS.md#web3-wallet-integration-add-token-or-network-to-the-wallet) (add token or network to the wallet) - [Verified tokens info](ENVS.md#verified-tokens-info) + - [SUAVE chain](ENVS.md#suave-chain) - [Sentry error monitoring](ENVS.md#sentry-error-monitoring) - [3rd party services configuration](ENVS.md#external-services-configuration) @@ -411,6 +412,16 @@ For the smart contract addresses which are [Safe{Core} accounts](https://safe.gl   +### SUAVE chain + +For blockchains that implementing SUAVE architecture additional fields will be shown on the transaction page ("Allowed peekers", "Computor"). Users also will be able to see the list of all transaction for a particular Computor in the separate view. + +| Variable | Type| Description | Compulsoriness | Default value | Example value | +| --- | --- | --- | --- | --- | --- | +| NEXT_PUBLIC_IS_SUAVE_CHAIN | `boolean` | Set to true for blockchains with [SUAVE architecture](https://writings.flashbots.net/mevm-suave-centauri-and-beyond) | Required | - | `true` | + +  + ### Sentry error monitoring | Variable | Type| Description | Compulsoriness | Default value | Example value | diff --git a/lib/api/resources.ts b/lib/api/resources.ts index f951716b7c..5f37871638 100644 --- a/lib/api/resources.ts +++ b/lib/api/resources.ts @@ -198,6 +198,11 @@ export const RESOURCES = { path: '/api/v2/transactions/watchlist', filterFields: [ ], }, + txs_execution_node: { + path: '/api/v2/transactions/execution-node/:hash', + pathParams: [ 'hash' as const ], + filterFields: [ ], + }, tx: { path: '/api/v2/transactions/:hash', pathParams: [ 'hash' as const ], @@ -533,7 +538,7 @@ export interface ResourceError { export type ResourceErrorAccount = ResourceError<{ errors: T }> export type PaginatedResources = 'blocks' | 'block_txs' | -'txs_validated' | 'txs_pending' | 'txs_watchlist' | +'txs_validated' | 'txs_pending' | 'txs_watchlist' | 'txs_execution_node' | 'tx_internal_txs' | 'tx_logs' | 'tx_token_transfers' | 'tx_state_changes' | 'addresses' | 'address_txs' | 'address_internal_txs' | 'address_token_transfers' | 'address_blocks_validated' | 'address_coin_balance' | @@ -577,6 +582,7 @@ Q extends 'block_withdrawals' ? BlockWithdrawalsResponse : Q extends 'txs_validated' ? TransactionsResponseValidated : Q extends 'txs_pending' ? TransactionsResponsePending : Q extends 'txs_watchlist' ? TransactionsResponseWatchlist : +Q extends 'txs_execution_node' ? TransactionsResponseValidated : Q extends 'tx' ? Transaction : Q extends 'tx_internal_txs' ? InternalTransactionsResponse : Q extends 'tx_logs' ? LogsResponseTx : diff --git a/lib/metadata/getPageOgType.ts b/lib/metadata/getPageOgType.ts index e8b4d0b002..91e1c9f234 100644 --- a/lib/metadata/getPageOgType.ts +++ b/lib/metadata/getPageOgType.ts @@ -5,6 +5,7 @@ type OGPageType = 'Homepage' | 'Root page' | 'Regular page'; const OG_TYPE_DICT: Record = { '/': 'Homepage', '/txs': 'Root page', + '/txs/computor/[hash]': 'Regular page', '/tx/[hash]': 'Regular page', '/blocks': 'Root page', '/block/[height_or_hash]': 'Regular page', diff --git a/lib/metadata/templates/description.ts b/lib/metadata/templates/description.ts index ddd7bbdc08..a8a5b5d93f 100644 --- a/lib/metadata/templates/description.ts +++ b/lib/metadata/templates/description.ts @@ -8,6 +8,7 @@ const DEFAULT_TEMPLATE = 'Blockscout is the #1 open-source blockchain explorer a const TEMPLATE_MAP: Record = { '/': DEFAULT_TEMPLATE, '/txs': DEFAULT_TEMPLATE, + '/txs/computor/[hash]': DEFAULT_TEMPLATE, '/tx/[hash]': 'View transaction %hash% on %network_title%', '/blocks': DEFAULT_TEMPLATE, '/block/[height_or_hash]': 'View the transactions, token transfers, and uncles for block %height_or_hash%', diff --git a/lib/metadata/templates/title.ts b/lib/metadata/templates/title.ts index dc37e8164c..b16abee393 100644 --- a/lib/metadata/templates/title.ts +++ b/lib/metadata/templates/title.ts @@ -3,6 +3,7 @@ import type { Route } from 'nextjs-routes'; const TEMPLATE_MAP: Record = { '/': 'blockchain explorer', '/txs': 'transactions', + '/txs/computor/[hash]': 'computor %hash% transactions', '/tx/[hash]': 'transaction %hash%', '/blocks': 'blocks', '/block/[height_or_hash]': 'block %height_or_hash%', diff --git a/lib/mixpanel/getPageType.ts b/lib/mixpanel/getPageType.ts index 6d21095222..02d1e11c6e 100644 --- a/lib/mixpanel/getPageType.ts +++ b/lib/mixpanel/getPageType.ts @@ -3,6 +3,7 @@ import type { Route } from 'nextjs-routes'; export const PAGE_TYPE_DICT: Record = { '/': 'Homepage', '/txs': 'Transactions', + '/txs/computor/[hash]': 'Computor transactions', '/tx/[hash]': 'Transaction details', '/blocks': 'Blocks', '/block/[height_or_hash]': 'Block details', diff --git a/nextjs/getServerSideProps.ts b/nextjs/getServerSideProps.ts index 48021b5614..f90e52043d 100644 --- a/nextjs/getServerSideProps.ts +++ b/nextjs/getServerSideProps.ts @@ -103,3 +103,13 @@ export const stats: GetServerSideProps = async(context) => { return base(context); }; + +export const suave: GetServerSideProps = async(context) => { + if (!config.features.suave.isEnabled) { + return { + notFound: true, + }; + } + + return base(context); +}; diff --git a/nextjs/nextjs-routes.d.ts b/nextjs/nextjs-routes.d.ts index cc38af5ad4..a7f05b9560 100644 --- a/nextjs/nextjs-routes.d.ts +++ b/nextjs/nextjs-routes.d.ts @@ -42,6 +42,7 @@ declare module "nextjs-routes" { | DynamicRoute<"/token/[hash]/instance/[id]", { "hash": string; "id": string }> | StaticRoute<"/tokens"> | DynamicRoute<"/tx/[hash]", { "hash": string }> + | DynamicRoute<"/txs/computor/[hash]", { "hash": string }> | StaticRoute<"/txs"> | StaticRoute<"/verified-contracts"> | StaticRoute<"/visualize/sol2uml"> diff --git a/pages/txs/computor/[hash].tsx b/pages/txs/computor/[hash].tsx new file mode 100644 index 0000000000..eb79606c0f --- /dev/null +++ b/pages/txs/computor/[hash].tsx @@ -0,0 +1,20 @@ +import type { NextPage } from 'next'; +import dynamic from 'next/dynamic'; +import React from 'react'; + +import type { Props } from 'nextjs/getServerSideProps'; +import PageNextJs from 'nextjs/PageNextJs'; + +const ComputorTxs = dynamic(() => import('ui/pages/ComputorTxs'), { ssr: false }); + +const Page: NextPage = (props: Props) => { + return ( + + + + ); +}; + +export default Page; + +export { suave as getServerSideProps } from 'nextjs/getServerSideProps'; diff --git a/pages/txs.tsx b/pages/txs/index.tsx similarity index 100% rename from pages/txs.tsx rename to pages/txs/index.tsx diff --git a/types/api/transaction.ts b/types/api/transaction.ts index d7ee8676a6..590e240eac 100644 --- a/types/api/transaction.ts +++ b/types/api/transaction.ts @@ -9,6 +9,9 @@ export type TransactionRevertReason = { raw: string; } | DecodedInput; +type WrappedTransactionFields = 'decoded_input' | 'fee' | 'gas_limit' | 'gas_price' | 'hash' | 'max_fee_per_gas' | +'max_priority_fee_per_gas' | 'method' | 'nonce' | 'raw_input' | 'to' | 'type' | 'value'; + export type Transaction = { to: AddressParam | null; created_contract: AddressParam | null; @@ -48,6 +51,10 @@ export type Transaction = { l1_gas_price?: string; l1_gas_used?: string; has_error_in_internal_txs: boolean | null; + // SUAVE fields + execution_node?: AddressParam | null; + allowed_peekers?: Array; + wrapped?: Pick; } export type TransactionsResponse = TransactionsResponseValidated | TransactionsResponsePending; diff --git a/types/utils.ts b/types/utils.ts index b3dea68b63..6a41f16f0c 100644 --- a/types/utils.ts +++ b/types/utils.ts @@ -4,4 +4,6 @@ export type ArrayElement = ArrType extends ReadonlyArray = T extends null ? never : T; +export type ExcludeUndefined = T extends undefined ? never : T; + export type KeysOfObjectOrNull = keyof ExcludeNull; diff --git a/ui/block/BlockDetails.tsx b/ui/block/BlockDetails.tsx index c5b7b9a40a..f37115e252 100644 --- a/ui/block/BlockDetails.tsx +++ b/ui/block/BlockDetails.tsx @@ -24,6 +24,7 @@ import Icon from 'ui/shared/chakra/Icon'; import CopyToClipboard from 'ui/shared/CopyToClipboard'; import DataFetchAlert from 'ui/shared/DataFetchAlert'; import DetailsInfoItem from 'ui/shared/DetailsInfoItem'; +import DetailsInfoItemDivider from 'ui/shared/DetailsInfoItemDivider'; import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import GasUsedToTargetRatio from 'ui/shared/GasUsedToTargetRatio'; import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic'; @@ -81,15 +82,6 @@ const BlockDetails = ({ query }: Props) => { return null; } - const sectionGap = ( - - ); const { totalReward, staticReward, burntFees, txFees } = getBlockReward(data); const validatorTitle = getNetworkValidatorTitle(); @@ -243,7 +235,7 @@ const BlockDetails = ({ query }: Props) => { )) } - { sectionGap } + { - { sectionGap } + { + const router = useRouter(); + + const hash = getQueryParamString(router.query.hash); + + const query = useQueryWithPages({ + resourceName: 'txs_execution_node', + pathParams: { hash }, + options: { + placeholderData: generateListStub<'txs_execution_node'>(TX, 50, { next_page_params: { + block_number: 9005713, + index: 5, + items_count: 50, + filter: 'validated', + } }), + }, + }); + + return ( + <> + + + + + ); +}; + +export default ComputorTxs; diff --git a/ui/pages/Transaction.tsx b/ui/pages/Transaction.tsx index b5757fbd0f..bb45943092 100644 --- a/ui/pages/Transaction.tsx +++ b/ui/pages/Transaction.tsx @@ -3,6 +3,7 @@ import React from 'react'; import type { RoutedTab } from 'ui/shared/Tabs/types'; +import config from 'configs/app'; import useApiQuery from 'lib/api/useApiQuery'; import { useAppContext } from 'lib/contexts/app'; import useIsMobile from 'lib/hooks/useIsMobile'; @@ -13,22 +14,16 @@ import EntityTags from 'ui/shared/EntityTags'; import NetworkExplorers from 'ui/shared/NetworkExplorers'; import PageTitle from 'ui/shared/Page/PageTitle'; import RoutedTabs from 'ui/shared/Tabs/RoutedTabs'; +import TabsSkeleton from 'ui/shared/Tabs/TabsSkeleton'; +import useTabIndexFromQuery from 'ui/shared/Tabs/useTabIndexFromQuery'; import TxDetails from 'ui/tx/TxDetails'; +import TxDetailsWrapped from 'ui/tx/TxDetailsWrapped'; import TxInternals from 'ui/tx/TxInternals'; import TxLogs from 'ui/tx/TxLogs'; import TxRawTrace from 'ui/tx/TxRawTrace'; import TxState from 'ui/tx/TxState'; import TxTokenTransfer from 'ui/tx/TxTokenTransfer'; -const TABS: Array = [ - { id: 'index', title: 'Details', component: }, - { id: 'token_transfers', title: 'Token transfers', component: }, - { id: 'internal', title: 'Internal txns', component: }, - { id: 'logs', title: 'Logs', component: }, - { id: 'state', title: 'State', component: }, - { id: 'raw_trace', title: 'Raw trace', component: }, -]; - const TransactionPageContent = () => { const router = useRouter(); const appProps = useAppContext(); @@ -44,6 +39,20 @@ const TransactionPageContent = () => { }, }); + const tabs: Array = [ + { id: 'index', title: config.features.suave.isEnabled && data?.wrapped ? 'Confidential compute tx details' : 'Details', component: }, + config.features.suave.isEnabled && data?.wrapped ? + { id: 'wrapped', title: 'Regular tx details', component: } : + undefined, + { id: 'token_transfers', title: 'Token transfers', component: }, + { id: 'internal', title: 'Internal txns', component: }, + { id: 'logs', title: 'Logs', component: }, + { id: 'state', title: 'State', component: }, + { id: 'raw_trace', title: 'Raw trace', component: }, + ].filter(Boolean); + + const tabIndex = useTabIndexFromQuery(tabs); + const tags = ( { backLink={ backLink } contentAfter={ tags } /> - + { isPlaceholderData ? ( + <> + + { tabs[tabIndex]?.component } + + ) : } ); }; diff --git a/ui/tokenInstance/details/TokenInstanceDivider.tsx b/ui/shared/DetailsInfoItemDivider.tsx similarity index 77% rename from ui/tokenInstance/details/TokenInstanceDivider.tsx rename to ui/shared/DetailsInfoItemDivider.tsx index 27d1830a09..22c5b456e0 100644 --- a/ui/tokenInstance/details/TokenInstanceDivider.tsx +++ b/ui/shared/DetailsInfoItemDivider.tsx @@ -1,7 +1,7 @@ import { GridItem } from '@chakra-ui/react'; import React from 'react'; -const TokenInstanceDivider = () => { +const DetailsInfoItemDivider = () => { return ( { ); }; -export default TokenInstanceDivider; +export default DetailsInfoItemDivider; diff --git a/ui/tokenInstance/TokenInstanceDetails.tsx b/ui/tokenInstance/TokenInstanceDetails.tsx index 5d05658656..e92d85fdbc 100644 --- a/ui/tokenInstance/TokenInstanceDetails.tsx +++ b/ui/tokenInstance/TokenInstanceDetails.tsx @@ -5,6 +5,7 @@ import type { TokenInstance } from 'types/api/token'; import CopyToClipboard from 'ui/shared/CopyToClipboard'; import DetailsInfoItem from 'ui/shared/DetailsInfoItem'; +import DetailsInfoItemDivider from 'ui/shared/DetailsInfoItemDivider'; import DetailsSponsoredItem from 'ui/shared/DetailsSponsoredItem'; import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import TokenEntity from 'ui/shared/entities/token/TokenEntity'; @@ -12,7 +13,6 @@ import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic'; import NftMedia from 'ui/shared/nft/NftMedia'; import TokenInstanceCreatorAddress from './details/TokenInstanceCreatorAddress'; -import TokenInstanceDivider from './details/TokenInstanceDivider'; import TokenInstanceMetadataInfo from './details/TokenInstanceMetadataInfo'; import TokenInstanceTransfersCount from './details/TokenInstanceTransfersCount'; @@ -99,7 +99,7 @@ const TokenInstanceDetails = ({ data, scrollRef, isLoading }: Props) => { overflow="hidden" > - + diff --git a/ui/tokenInstance/details/TokenInstanceMetadataInfo.tsx b/ui/tokenInstance/details/TokenInstanceMetadataInfo.tsx index 5855f550b4..17720a0aaa 100644 --- a/ui/tokenInstance/details/TokenInstanceMetadataInfo.tsx +++ b/ui/tokenInstance/details/TokenInstanceMetadataInfo.tsx @@ -6,11 +6,10 @@ import type { MetadataAttributes } from 'types/client/token'; import parseMetadata from 'lib/token/parseMetadata'; import DetailsInfoItem from 'ui/shared/DetailsInfoItem'; +import DetailsInfoItemDivider from 'ui/shared/DetailsInfoItemDivider'; import LinkExternal from 'ui/shared/LinkExternal'; import TruncatedValue from 'ui/shared/TruncatedValue'; -import TokenInstanceDivider from './TokenInstanceDivider'; - interface Props { data?: TokenInstance; isLoading?: boolean; @@ -71,7 +70,7 @@ const TokenInstanceMetadataInfo = ({ data, isLoading }: Props) => { return ( <> - + { metadata?.name && ( ; +} + +const CUT_LENGTH = 2; + +const TxAllowedPeekers = ({ items }: Props) => { + const [ isExpanded, expand ] = useBoolean(false); + + return ( + + + { items + .slice(0, isExpanded ? undefined : CUT_LENGTH) + .map((item) => ) } + + { items.length > CUT_LENGTH && ( + + { isExpanded ? 'Hide' : 'Show all' } + + ) } + + ); +}; + +export default React.memo(TxAllowedPeekers); diff --git a/ui/tx/TxDetails.tsx b/ui/tx/TxDetails.tsx index b9b4362591..5555581263 100644 --- a/ui/tx/TxDetails.tsx +++ b/ui/tx/TxDetails.tsx @@ -17,6 +17,8 @@ import BigNumber from 'bignumber.js'; import React from 'react'; import { scroller, Element } from 'react-scroll'; +import { route } from 'nextjs-routes'; + import config from 'configs/app'; import clockIcon from 'icons/clock.svg'; import flameIcon from 'icons/flame.svg'; @@ -32,6 +34,7 @@ import CopyToClipboard from 'ui/shared/CopyToClipboard'; import CurrencyValue from 'ui/shared/CurrencyValue'; import DataFetchAlert from 'ui/shared/DataFetchAlert'; import DetailsInfoItem from 'ui/shared/DetailsInfoItem'; +import DetailsInfoItemDivider from 'ui/shared/DetailsInfoItemDivider'; import DetailsSponsoredItem from 'ui/shared/DetailsSponsoredItem'; import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import BlockEntity from 'ui/shared/entities/block/BlockEntity'; @@ -42,8 +45,11 @@ import TextSeparator from 'ui/shared/TextSeparator'; import TxStatus from 'ui/shared/TxStatus'; import Utilization from 'ui/shared/Utilization/Utilization'; import TxDetailsActions from 'ui/tx/details/TxDetailsActions'; +import TxDetailsGasPrice from 'ui/tx/details/TxDetailsGasPrice'; +import TxDetailsOther from 'ui/tx/details/TxDetailsOther'; import TxDetailsTokenTransfers from 'ui/tx/details/TxDetailsTokenTransfers'; import TxRevertReason from 'ui/tx/details/TxRevertReason'; +import TxAllowedPeekers from 'ui/tx/TxAllowedPeekers'; import TxSocketAlert from 'ui/tx/TxSocketAlert'; import useFetchTxInfo from 'ui/tx/useFetchTxInfo'; @@ -107,19 +113,13 @@ const TxDetails = () => { ) : null; - const divider = ( - - ); - return ( <> - { config.chain.isTestnet && This is a testnet transaction only } + { config.chain.isTestnet && ( + + This is a testnet transaction only + + ) } { socketStatus && ( @@ -196,14 +196,29 @@ const TxDetails = () => { ) } + { data.execution_node && ( + + + + ) } + { data.allowed_peekers && data.allowed_peekers.length > 0 && ( + + ) } - { divider } + { actionsExist && ( <> - { divider } + ) } @@ -267,7 +282,7 @@ const TxDetails = () => { { data.token_transfers && } - { divider } + { isLoading={ isPlaceholderData } /> - - - { BigNumber(data.gas_price).dividedBy(WEI).toFixed() } { config.chain.currency.symbol } - - - ({ BigNumber(data.gas_price).dividedBy(WEI_IN_GWEI).toFixed() } Gwei) - - + { { isExpanded && ( <> - - { - [ - typeof data.type === 'number' && ( - - Txn type: - { data.type } - { data.type === 2 && (EIP-1559) } - - ), - - Nonce: - { data.nonce } - , - data.position !== null && ( - - Position: - { data.position } - - ), - ] - .filter(Boolean) - .map((item, index) => ( - <> - { index !== 0 && } - { item } - - )) - } - + ; +} + +const TxDetailsWrapped = ({ data }: Props) => { + return ( + + + + + + + { data.method } + + + + + + + + + + + + + + + + + + + + + { data.gas_limit && ( + + { BigNumber(data.gas_limit).toFormat() } + + ) } + + + + + + + + { data.decoded_input && ( + + + + ) } + + ); +}; + +export default TxDetailsWrapped; diff --git a/ui/tx/details/TxDetailsGasPrice.tsx b/ui/tx/details/TxDetailsGasPrice.tsx new file mode 100644 index 0000000000..bccae8deb6 --- /dev/null +++ b/ui/tx/details/TxDetailsGasPrice.tsx @@ -0,0 +1,31 @@ +import { Skeleton } from '@chakra-ui/react'; +import BigNumber from 'bignumber.js'; +import React from 'react'; + +import config from 'configs/app'; +import { WEI, WEI_IN_GWEI } from 'lib/consts'; +import DetailsInfoItem from 'ui/shared/DetailsInfoItem'; + +interface Props { + gasPrice: string; + isLoading?: boolean; +} + +const TxDetailsGasPrice = ({ gasPrice, isLoading }: Props) => { + return ( + + + { BigNumber(gasPrice).dividedBy(WEI).toFixed() } { config.chain.currency.symbol } + + + ({ BigNumber(gasPrice).dividedBy(WEI_IN_GWEI).toFixed() } Gwei) + + + ); +}; + +export default TxDetailsGasPrice; diff --git a/ui/tx/details/TxDetailsOther.tsx b/ui/tx/details/TxDetailsOther.tsx new file mode 100644 index 0000000000..97f5d4114a --- /dev/null +++ b/ui/tx/details/TxDetailsOther.tsx @@ -0,0 +1,49 @@ +import { Box, Text } from '@chakra-ui/react'; +import React from 'react'; + +import type { Transaction } from 'types/api/transaction'; + +import DetailsInfoItem from 'ui/shared/DetailsInfoItem'; +import TextSeparator from 'ui/shared/TextSeparator'; + +type Props = Pick + +const TxDetailsOther = ({ nonce, type, position }: Props) => { + return ( + + { + [ + typeof type === 'number' && ( + + Txn type: + { type } + { type === 2 && (EIP-1559) } + + ), + + Nonce: + { nonce } + , + position !== null && position !== undefined && ( + + Position: + { position } + + ), + ] + .filter(Boolean) + .map((item, index) => ( + <> + { index !== 0 && } + { item } + + )) + } + + ); +}; + +export default TxDetailsOther;