mirror of
https://github.com/luxfi/explore.git
synced 2026-09-24 00:28:18 +00:00
user ops
This commit is contained in:
+2
-2
@@ -5,12 +5,12 @@ import React from 'react';
|
||||
import type { Props } from 'nextjs/getServerSideProps';
|
||||
import PageNextJs from 'nextjs/PageNextJs';
|
||||
|
||||
// const UserOp = dynamic(() => import('ui/pages/UserOp'), { ssr: false });
|
||||
const UserOp = dynamic(() => import('ui/pages/UserOp'), { ssr: false });
|
||||
|
||||
const Page: NextPage<Props> = (props: Props) => {
|
||||
return (
|
||||
<PageNextJs pathname="/op/[hash]" query={ props.query }>
|
||||
{ /* <UserOp/> */ }
|
||||
<UserOp/>
|
||||
</PageNextJs>
|
||||
);
|
||||
};
|
||||
|
||||
+2
-2
@@ -4,12 +4,12 @@ import React from 'react';
|
||||
|
||||
import PageNextJs from 'nextjs/PageNextJs';
|
||||
|
||||
// const UserOps = dynamic(() => import('ui/pages/UserOps'), { ssr: false });
|
||||
const UserOps = dynamic(() => import('ui/pages/UserOps'), { ssr: false });
|
||||
|
||||
const Page: NextPage = () => {
|
||||
return (
|
||||
<PageNextJs pathname="/ops">
|
||||
{ /* <UserOps/> */ }
|
||||
<UserOps/>
|
||||
</PageNextJs>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -3,6 +3,7 @@ import * as React from 'react';
|
||||
|
||||
export interface SwitchProps extends ChakraSwitch.RootProps {
|
||||
inputProps?: React.InputHTMLAttributes<HTMLInputElement>;
|
||||
labelProps?: ChakraSwitch.LabelProps;
|
||||
rootRef?: React.Ref<HTMLLabelElement>;
|
||||
trackLabel?: { on: React.ReactNode; off: React.ReactNode };
|
||||
thumbLabel?: { on: React.ReactNode; off: React.ReactNode };
|
||||
@@ -10,7 +11,7 @@ export interface SwitchProps extends ChakraSwitch.RootProps {
|
||||
|
||||
export const Switch = React.forwardRef<HTMLInputElement, SwitchProps>(
|
||||
function Switch(props, ref) {
|
||||
const { inputProps, children, rootRef, trackLabel, thumbLabel, ...rest } =
|
||||
const { inputProps, children, rootRef, trackLabel, thumbLabel, labelProps, ...rest } =
|
||||
props;
|
||||
|
||||
return (
|
||||
@@ -31,7 +32,7 @@ export const Switch = React.forwardRef<HTMLInputElement, SwitchProps>(
|
||||
) }
|
||||
</ChakraSwitch.Control >
|
||||
{ children != null && (
|
||||
<ChakraSwitch.Label>{ children }</ChakraSwitch.Label>
|
||||
<ChakraSwitch.Label { ...labelProps }>{ children }</ChakraSwitch.Label>
|
||||
) }
|
||||
</ChakraSwitch.Root>
|
||||
);
|
||||
|
||||
+8
-8
@@ -2,9 +2,9 @@ import { inRange } from 'es-toolkit';
|
||||
import { useRouter } from 'next/router';
|
||||
import React from 'react';
|
||||
|
||||
import type { TabItemRegular } from 'toolkit/components/AdaptiveTabs/types';
|
||||
import type { Log } from 'types/api/log';
|
||||
import type { TokenTransfer } from 'types/api/tokenTransfer';
|
||||
import type { RoutedTab } from 'ui/shared/Tabs/types';
|
||||
|
||||
import useApiQuery from 'lib/api/useApiQuery';
|
||||
import { useAppContext } from 'lib/contexts/app';
|
||||
@@ -12,11 +12,11 @@ import throwOnAbsentParamError from 'lib/errors/throwOnAbsentParamError';
|
||||
import throwOnResourceLoadError from 'lib/errors/throwOnResourceLoadError';
|
||||
import getQueryParamString from 'lib/router/getQueryParamString';
|
||||
import { USER_OP } from 'stubs/userOps';
|
||||
import RoutedTabs from 'toolkit/components/RoutedTabs/RoutedTabs';
|
||||
import RoutedTabsSkeleton from 'toolkit/components/RoutedTabs/RoutedTabsSkeleton';
|
||||
import useActiveTabFromQuery from 'toolkit/components/RoutedTabs/useActiveTabFromQuery';
|
||||
import TextAd from 'ui/shared/ad/TextAd';
|
||||
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 TxLogs from 'ui/tx/TxLogs';
|
||||
import TxTokenTransfer from 'ui/tx/TxTokenTransfer';
|
||||
import useTxQuery from 'ui/tx/useTxQuery';
|
||||
@@ -65,7 +65,7 @@ const UserOp = () => {
|
||||
}
|
||||
}, [ userOpQuery.data ]);
|
||||
|
||||
const tabs: Array<RoutedTab> = React.useMemo(() => ([
|
||||
const tabs: Array<TabItemRegular> = React.useMemo(() => ([
|
||||
{ id: 'index', title: 'Details', component: <UserOpDetails query={ userOpQuery }/> },
|
||||
{
|
||||
id: 'token_transfers',
|
||||
@@ -76,7 +76,7 @@ const UserOp = () => {
|
||||
{ id: 'raw', title: 'Raw', component: <UserOpRaw rawData={ userOpQuery.data?.raw } isLoading={ userOpQuery.isPlaceholderData }/> },
|
||||
]), [ userOpQuery, txQuery, filterTokenTransfersByLogIndex, filterLogsByLogIndex ]);
|
||||
|
||||
const tabIndex = useTabIndexFromQuery(tabs);
|
||||
const activeTab = useActiveTabFromQuery(tabs);
|
||||
|
||||
const backLink = React.useMemo(() => {
|
||||
const hasGoBackLink = appProps.referrer && appProps.referrer.includes('/ops');
|
||||
@@ -106,8 +106,8 @@ const UserOp = () => {
|
||||
/>
|
||||
{ userOpQuery.isPlaceholderData ? (
|
||||
<>
|
||||
<TabsSkeleton tabs={ tabs } mt={ 6 }/>
|
||||
{ tabs[tabIndex]?.component }
|
||||
<RoutedTabsSkeleton tabs={ tabs } mt={ 6 }/>
|
||||
{ activeTab?.component }
|
||||
</>
|
||||
) :
|
||||
<RoutedTabs tabs={ tabs }/> }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { FlexProps } from '@chakra-ui/react';
|
||||
import { Flex, chakra } from '@chakra-ui/react';
|
||||
import { Flex } from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
|
||||
export interface Props extends FlexProps {
|
||||
@@ -44,4 +44,4 @@ const ContainerWithScrollY = ({ gradientHeight, children, onScrollVisibilityChan
|
||||
);
|
||||
};
|
||||
|
||||
export default chakra(ContainerWithScrollY);
|
||||
export default ContainerWithScrollY;
|
||||
|
||||
@@ -73,11 +73,11 @@ export const ItemValue = ({ children, ...rest }: ItemValueProps) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const ItemValueWithScroll = ({ children, gradientHeight, onScrollVisibilityChange, className }: ContainerWithScrollY.Props) => {
|
||||
export const ItemValueWithScroll = ({ children, gradientHeight, onScrollVisibilityChange, ...rest }: ContainerWithScrollY.Props) => {
|
||||
return (
|
||||
<ItemValue position="relative">
|
||||
<ItemValue position="relative" >
|
||||
<ContainerWithScrollY.default
|
||||
className={ className }
|
||||
{ ...rest }
|
||||
gradientHeight={ gradientHeight }
|
||||
onScrollVisibilityChange={ onScrollVisibilityChange }
|
||||
>
|
||||
|
||||
@@ -63,13 +63,12 @@ export interface EntityProps extends EntityBase.EntityBaseProps {
|
||||
|
||||
const UserOpEntity = (props: EntityProps) => {
|
||||
const partsProps = distributeEntityProps(props);
|
||||
const content = <Content { ...partsProps.content }/>;
|
||||
|
||||
return (
|
||||
<Container { ...partsProps.container }>
|
||||
<Icon { ...partsProps.icon }/>
|
||||
<Link { ...partsProps.link }>
|
||||
<Content { ...partsProps.content }/>
|
||||
</Link>
|
||||
{ props.noLink ? content : <Link { ...partsProps.link }>{ content }</Link> }
|
||||
<Copy { ...partsProps.copy }/>
|
||||
</Container>
|
||||
);
|
||||
|
||||
@@ -125,7 +125,7 @@ const TxInterpretationElementByType = (
|
||||
case 'method': {
|
||||
return (
|
||||
<Badge
|
||||
colorScheme={ value === 'Multicall' ? 'teal' : 'gray' }
|
||||
colorPalette={ value === 'Multicall' ? 'teal' : 'gray' }
|
||||
truncated
|
||||
ml={ 1 }
|
||||
mr={ 2 }
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { Tag } from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
|
||||
import type { UserOpSponsorType as TUserOpSponsorType } from 'types/api/userOps';
|
||||
|
||||
import { Badge } from 'toolkit/chakra/badge';
|
||||
|
||||
type Props = {
|
||||
sponsorType: TUserOpSponsorType;
|
||||
};
|
||||
@@ -22,7 +23,7 @@ const UserOpSponsorType = ({ sponsorType }: Props) => {
|
||||
case 'wallet_deposit':
|
||||
text = 'Wallet deposit';
|
||||
}
|
||||
return <Tag>{ text }</Tag>;
|
||||
return <Badge>{ text }</Badge>;
|
||||
};
|
||||
|
||||
export default UserOpSponsorType;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { chakra, FormLabel, FormControl, Switch } from '@chakra-ui/react';
|
||||
import { chakra, Flex } from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
|
||||
import { Switch } from 'toolkit/chakra/switch';
|
||||
import Hint from 'ui/shared/Hint';
|
||||
|
||||
interface Props {
|
||||
@@ -22,13 +23,23 @@ const UserOpCallDataSwitch = ({ className, initialValue, isDisabled, onChange }:
|
||||
}, [ onChange ]);
|
||||
|
||||
return (
|
||||
<FormControl className={ className } display="flex" columnGap={ 2 } ml="auto" w="fit-content">
|
||||
<FormLabel htmlFor="isExternal" fontSize="sm" lineHeight={ 5 } fontWeight={ 600 } m={ 0 }>
|
||||
Show external call data
|
||||
</FormLabel>
|
||||
<Switch id="isExternal" isChecked={ isChecked } isDisabled={ isDisabled } onChange={ handleChange }/>
|
||||
<Flex ml="auto" alignItems="center" gap={ 2 }>
|
||||
<Switch
|
||||
className={ className }
|
||||
id="call-data-switch"
|
||||
checked={ isChecked }
|
||||
disabled={ isDisabled }
|
||||
onCheckedChange={ handleChange }
|
||||
flexDirection="row-reverse"
|
||||
size="md"
|
||||
gap={ 2 }
|
||||
labelProps={{ fontWeight: '600', fontSize: 'sm' }}
|
||||
>
|
||||
<chakra.span hideBelow="lg">Show external call data</chakra.span>
|
||||
<chakra.span hideFrom="lg">External call data</chakra.span>
|
||||
</Switch>
|
||||
<Hint label="Inner call data is a predicted decoded call from this user operation"/>
|
||||
</FormControl>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
+150
-181
@@ -1,8 +1,7 @@
|
||||
import { Grid, GridItem, Text, Link } from '@chakra-ui/react';
|
||||
import { Grid, GridItem, Text } from '@chakra-ui/react';
|
||||
import type { UseQueryResult } from '@tanstack/react-query';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import React from 'react';
|
||||
import { scroller, Element } from 'react-scroll';
|
||||
|
||||
import type { UserOp } from 'types/api/userOps';
|
||||
|
||||
@@ -12,12 +11,12 @@ import { WEI, WEI_IN_GWEI } from 'lib/consts';
|
||||
import throwOnResourceLoadError from 'lib/errors/throwOnResourceLoadError';
|
||||
import { space } from 'lib/html-entities';
|
||||
import { currencyUnits } from 'lib/units';
|
||||
import { Skeleton } from 'toolkit/chakra/skeleton';
|
||||
import CutLinkDetails from 'toolkit/components/CutLink/CutLinkDetails';
|
||||
import isCustomAppError from 'ui/shared/AppError/isCustomAppError';
|
||||
import Skeleton from 'ui/shared/chakra/Skeleton';
|
||||
import CurrencyValue from 'ui/shared/CurrencyValue';
|
||||
import DataFetchAlert from 'ui/shared/DataFetchAlert';
|
||||
import * as DetailedInfo from 'ui/shared/DetailedInfo/DetailedInfo';
|
||||
|
||||
import DetailedInfoTimestamp from 'ui/shared/DetailedInfo/DetailedInfoTimestamp';
|
||||
import AddressStringOrParam from 'ui/shared/entities/address/AddressStringOrParam';
|
||||
import BlockEntity from 'ui/shared/entities/block/BlockEntity';
|
||||
@@ -35,21 +34,9 @@ interface Props {
|
||||
query: UseQueryResult<UserOp, ResourceError>;
|
||||
}
|
||||
|
||||
const CUT_LINK_NAME = 'UserOpDetails__cutLink';
|
||||
|
||||
const UserOpDetails = ({ query }: Props) => {
|
||||
const [ isExpanded, setIsExpanded ] = React.useState(false);
|
||||
|
||||
const { data, isPlaceholderData, isError, error } = query;
|
||||
|
||||
const handleCutClick = React.useCallback(() => {
|
||||
setIsExpanded((flag) => !flag);
|
||||
scroller.scrollTo(CUT_LINK_NAME, {
|
||||
duration: 500,
|
||||
smooth: true,
|
||||
});
|
||||
}, []);
|
||||
|
||||
if (isError) {
|
||||
if (error?.status === 400 || isCustomAppError(error)) {
|
||||
throwOnResourceLoadError({ isError, error });
|
||||
@@ -76,7 +63,7 @@ const UserOpDetails = ({ query }: Props) => {
|
||||
User operation hash
|
||||
</DetailedInfo.ItemLabel>
|
||||
<DetailedInfo.ItemValue>
|
||||
<Skeleton isLoaded={ !isPlaceholderData } overflow="hidden">
|
||||
<Skeleton loading={ isPlaceholderData } overflow="hidden">
|
||||
<UserOpEntity hash={ data.hash } noIcon noLink noCopy={ false }/>
|
||||
</Skeleton>
|
||||
</DetailedInfo.ItemValue>
|
||||
@@ -113,7 +100,7 @@ const UserOpDetails = ({ query }: Props) => {
|
||||
wordBreak="break-all"
|
||||
whiteSpace="normal"
|
||||
>
|
||||
<Skeleton isLoaded={ !isPlaceholderData }>
|
||||
<Skeleton loading={ isPlaceholderData }>
|
||||
{ data.revert_reason }
|
||||
</Skeleton>
|
||||
</DetailedInfo.ItemValue>
|
||||
@@ -159,7 +146,7 @@ const UserOpDetails = ({ query }: Props) => {
|
||||
Gas limit
|
||||
</DetailedInfo.ItemLabel>
|
||||
<DetailedInfo.ItemValue>
|
||||
<Skeleton isLoaded={ !isPlaceholderData }>
|
||||
<Skeleton loading={ isPlaceholderData }>
|
||||
{ BigNumber(data.gas).toFormat() }
|
||||
</Skeleton>
|
||||
</DetailedInfo.ItemValue>
|
||||
@@ -171,7 +158,7 @@ const UserOpDetails = ({ query }: Props) => {
|
||||
Gas used
|
||||
</DetailedInfo.ItemLabel>
|
||||
<DetailedInfo.ItemValue>
|
||||
<Skeleton isLoaded={ !isPlaceholderData }>
|
||||
<Skeleton loading={ isPlaceholderData }>
|
||||
{ BigNumber(data.gas_used).toFormat() }
|
||||
</Skeleton>
|
||||
<Utilization
|
||||
@@ -214,185 +201,167 @@ const UserOpDetails = ({ query }: Props) => {
|
||||
|
||||
{ config.features.txInterpretation.isEnabled && <UserOpDetailsActions hash={ data.hash } isUserOpDataLoading={ isPlaceholderData }/> }
|
||||
|
||||
{ /* CUT */ }
|
||||
<GridItem colSpan={{ base: undefined, lg: 2 }}>
|
||||
<Element name={ CUT_LINK_NAME }>
|
||||
<Skeleton isLoaded={ !isPlaceholderData } mt={ 6 } display="inline-block">
|
||||
<Link
|
||||
fontSize="sm"
|
||||
textDecorationLine="underline"
|
||||
textDecorationStyle="dashed"
|
||||
onClick={ handleCutClick }
|
||||
>
|
||||
{ isExpanded ? 'Hide details' : 'View details' }
|
||||
</Link>
|
||||
</Skeleton>
|
||||
</Element>
|
||||
</GridItem>
|
||||
|
||||
{ /* ADDITIONAL INFO */ }
|
||||
{ isExpanded && !isPlaceholderData && (
|
||||
<>
|
||||
<GridItem colSpan={{ base: undefined, lg: 2 }} mt={{ base: 1, lg: 4 }}/>
|
||||
<CutLinkDetails loading={ isPlaceholderData } mt={ 6 } gridColumn={{ base: undefined, lg: '1 / 3' }}>
|
||||
<GridItem colSpan={{ base: undefined, lg: 2 }} mt={{ base: 1, lg: 4 }}/>
|
||||
|
||||
<DetailedInfo.ItemLabel
|
||||
hint="Gas limit for execution phase"
|
||||
>
|
||||
Call gas limit
|
||||
</DetailedInfo.ItemLabel>
|
||||
<DetailedInfo.ItemValue>
|
||||
{ BigNumber(data.call_gas_limit).toFormat() }
|
||||
</DetailedInfo.ItemValue>
|
||||
<DetailedInfo.ItemLabel
|
||||
hint="Gas limit for execution phase"
|
||||
>
|
||||
Call gas limit
|
||||
</DetailedInfo.ItemLabel>
|
||||
<DetailedInfo.ItemValue>
|
||||
{ BigNumber(data.call_gas_limit).toFormat() }
|
||||
</DetailedInfo.ItemValue>
|
||||
|
||||
<DetailedInfo.ItemLabel
|
||||
hint="Gas limit for verification phase"
|
||||
>
|
||||
Verification gas limit
|
||||
</DetailedInfo.ItemLabel>
|
||||
<DetailedInfo.ItemValue>
|
||||
{ BigNumber(data.verification_gas_limit).toFormat() }
|
||||
</DetailedInfo.ItemValue>
|
||||
<DetailedInfo.ItemLabel
|
||||
hint="Gas limit for verification phase"
|
||||
>
|
||||
Verification gas limit
|
||||
</DetailedInfo.ItemLabel>
|
||||
<DetailedInfo.ItemValue>
|
||||
{ BigNumber(data.verification_gas_limit).toFormat() }
|
||||
</DetailedInfo.ItemValue>
|
||||
|
||||
<DetailedInfo.ItemLabel
|
||||
hint="Gas to compensate the bundler"
|
||||
>
|
||||
Pre-verification gas
|
||||
</DetailedInfo.ItemLabel>
|
||||
<DetailedInfo.ItemValue>
|
||||
{ BigNumber(data.pre_verification_gas).toFormat() }
|
||||
</DetailedInfo.ItemValue>
|
||||
<DetailedInfo.ItemLabel
|
||||
hint="Gas to compensate the bundler"
|
||||
>
|
||||
Pre-verification gas
|
||||
</DetailedInfo.ItemLabel>
|
||||
<DetailedInfo.ItemValue>
|
||||
{ BigNumber(data.pre_verification_gas).toFormat() }
|
||||
</DetailedInfo.ItemValue>
|
||||
|
||||
{ !config.UI.views.tx.hiddenFields?.gas_fees && (
|
||||
<>
|
||||
<DetailedInfo.ItemLabel
|
||||
hint="Maximum fee per gas "
|
||||
>
|
||||
Max fee per gas
|
||||
</DetailedInfo.ItemLabel>
|
||||
<DetailedInfo.ItemValue>
|
||||
<Text>{ BigNumber(data.max_fee_per_gas).dividedBy(WEI).toFixed() } { currencyUnits.ether } </Text>
|
||||
<Text variant="secondary" whiteSpace="pre">
|
||||
{ space }({ BigNumber(data.max_fee_per_gas).dividedBy(WEI_IN_GWEI).toFixed() } { currencyUnits.gwei })
|
||||
</Text>
|
||||
</DetailedInfo.ItemValue>
|
||||
{ !config.UI.views.tx.hiddenFields?.gas_fees && (
|
||||
<>
|
||||
<DetailedInfo.ItemLabel
|
||||
hint="Maximum fee per gas "
|
||||
>
|
||||
Max fee per gas
|
||||
</DetailedInfo.ItemLabel>
|
||||
<DetailedInfo.ItemValue>
|
||||
<Text>{ BigNumber(data.max_fee_per_gas).dividedBy(WEI).toFixed() } { currencyUnits.ether } </Text>
|
||||
<Text color="text.secondary" whiteSpace="pre">
|
||||
{ space }({ BigNumber(data.max_fee_per_gas).dividedBy(WEI_IN_GWEI).toFixed() } { currencyUnits.gwei })
|
||||
</Text>
|
||||
</DetailedInfo.ItemValue>
|
||||
|
||||
<DetailedInfo.ItemLabel
|
||||
hint="Maximum priority fee per gas"
|
||||
>
|
||||
Max priority fee per gas
|
||||
</DetailedInfo.ItemLabel>
|
||||
<DetailedInfo.ItemValue>
|
||||
<Text>{ BigNumber(data.max_priority_fee_per_gas).dividedBy(WEI).toFixed() } { currencyUnits.ether } </Text>
|
||||
<Text variant="secondary" whiteSpace="pre">
|
||||
{ space }({ BigNumber(data.max_priority_fee_per_gas).dividedBy(WEI_IN_GWEI).toFixed() } { currencyUnits.gwei })
|
||||
</Text>
|
||||
</DetailedInfo.ItemValue>
|
||||
</>
|
||||
) }
|
||||
<DetailedInfo.ItemLabel
|
||||
hint="Maximum priority fee per gas"
|
||||
>
|
||||
Max priority fee per gas
|
||||
</DetailedInfo.ItemLabel>
|
||||
<DetailedInfo.ItemValue>
|
||||
<Text>{ BigNumber(data.max_priority_fee_per_gas).dividedBy(WEI).toFixed() } { currencyUnits.ether } </Text>
|
||||
<Text color="text.secondary" whiteSpace="pre">
|
||||
{ space }({ BigNumber(data.max_priority_fee_per_gas).dividedBy(WEI_IN_GWEI).toFixed() } { currencyUnits.gwei })
|
||||
</Text>
|
||||
</DetailedInfo.ItemValue>
|
||||
</>
|
||||
) }
|
||||
|
||||
<DetailedInfo.ItemDivider/>
|
||||
<DetailedInfo.ItemDivider/>
|
||||
|
||||
{ data.aggregator && (
|
||||
<>
|
||||
<DetailedInfo.ItemLabel
|
||||
hint="Helper contract to validate an aggregated signature"
|
||||
>
|
||||
Aggregator
|
||||
</DetailedInfo.ItemLabel>
|
||||
<DetailedInfo.ItemValue>
|
||||
<AddressStringOrParam address={ data.aggregator }/>
|
||||
</DetailedInfo.ItemValue>
|
||||
</>
|
||||
) }
|
||||
{ data.aggregator && (
|
||||
<>
|
||||
<DetailedInfo.ItemLabel
|
||||
hint="Helper contract to validate an aggregated signature"
|
||||
>
|
||||
Aggregator
|
||||
</DetailedInfo.ItemLabel>
|
||||
<DetailedInfo.ItemValue>
|
||||
<AddressStringOrParam address={ data.aggregator }/>
|
||||
</DetailedInfo.ItemValue>
|
||||
</>
|
||||
) }
|
||||
|
||||
{ data.aggregator_signature && (
|
||||
<>
|
||||
<DetailedInfo.ItemLabel
|
||||
hint="Aggregator signature"
|
||||
>
|
||||
Aggregator signature
|
||||
</DetailedInfo.ItemLabel>
|
||||
<DetailedInfo.ItemValue>
|
||||
{ data.aggregator_signature }
|
||||
</DetailedInfo.ItemValue>
|
||||
</>
|
||||
) }
|
||||
{ data.aggregator_signature && (
|
||||
<>
|
||||
<DetailedInfo.ItemLabel
|
||||
hint="Aggregator signature"
|
||||
>
|
||||
Aggregator signature
|
||||
</DetailedInfo.ItemLabel>
|
||||
<DetailedInfo.ItemValue>
|
||||
{ data.aggregator_signature }
|
||||
</DetailedInfo.ItemValue>
|
||||
</>
|
||||
) }
|
||||
|
||||
<DetailedInfo.ItemLabel
|
||||
hint="A node (block builder) that handles User operations"
|
||||
>
|
||||
Bundler
|
||||
</DetailedInfo.ItemLabel>
|
||||
<DetailedInfo.ItemValue>
|
||||
<AddressStringOrParam address={ data.bundler }/>
|
||||
</DetailedInfo.ItemValue>
|
||||
<DetailedInfo.ItemLabel
|
||||
hint="A node (block builder) that handles User operations"
|
||||
>
|
||||
Bundler
|
||||
</DetailedInfo.ItemLabel>
|
||||
<DetailedInfo.ItemValue>
|
||||
<AddressStringOrParam address={ data.bundler }/>
|
||||
</DetailedInfo.ItemValue>
|
||||
|
||||
{ data.factory && (
|
||||
<>
|
||||
<DetailedInfo.ItemLabel
|
||||
hint="Smart contract that deploys new smart contract wallets for users"
|
||||
>
|
||||
Factory
|
||||
</DetailedInfo.ItemLabel>
|
||||
<DetailedInfo.ItemValue>
|
||||
<AddressStringOrParam address={ data.factory }/>
|
||||
</DetailedInfo.ItemValue>
|
||||
</>
|
||||
) }
|
||||
{ data.factory && (
|
||||
<>
|
||||
<DetailedInfo.ItemLabel
|
||||
hint="Smart contract that deploys new smart contract wallets for users"
|
||||
>
|
||||
Factory
|
||||
</DetailedInfo.ItemLabel>
|
||||
<DetailedInfo.ItemValue>
|
||||
<AddressStringOrParam address={ data.factory }/>
|
||||
</DetailedInfo.ItemValue>
|
||||
</>
|
||||
) }
|
||||
|
||||
{ data.paymaster && (
|
||||
<>
|
||||
<DetailedInfo.ItemLabel
|
||||
hint="Contract to sponsor the gas fees for User operations"
|
||||
>
|
||||
Paymaster
|
||||
</DetailedInfo.ItemLabel>
|
||||
<DetailedInfo.ItemValue>
|
||||
<AddressStringOrParam address={ data.paymaster }/>
|
||||
</DetailedInfo.ItemValue>
|
||||
</>
|
||||
) }
|
||||
{ data.paymaster && (
|
||||
<>
|
||||
<DetailedInfo.ItemLabel
|
||||
hint="Contract to sponsor the gas fees for User operations"
|
||||
>
|
||||
Paymaster
|
||||
</DetailedInfo.ItemLabel>
|
||||
<DetailedInfo.ItemValue>
|
||||
<AddressStringOrParam address={ data.paymaster }/>
|
||||
</DetailedInfo.ItemValue>
|
||||
</>
|
||||
) }
|
||||
|
||||
<DetailedInfo.ItemLabel
|
||||
hint="Type of the gas fees sponsor"
|
||||
>
|
||||
Sponsor type
|
||||
</DetailedInfo.ItemLabel>
|
||||
<DetailedInfo.ItemValue>
|
||||
<UserOpSponsorType sponsorType={ data.sponsor_type }/>
|
||||
</DetailedInfo.ItemValue>
|
||||
<DetailedInfo.ItemLabel
|
||||
hint="Type of the gas fees sponsor"
|
||||
>
|
||||
Sponsor type
|
||||
</DetailedInfo.ItemLabel>
|
||||
<DetailedInfo.ItemValue>
|
||||
<UserOpSponsorType sponsorType={ data.sponsor_type }/>
|
||||
</DetailedInfo.ItemValue>
|
||||
|
||||
<DetailedInfo.ItemDivider/>
|
||||
<DetailedInfo.ItemDivider/>
|
||||
|
||||
<DetailedInfo.ItemLabel
|
||||
hint="Used to validate a User operation along with the nonce during verification"
|
||||
>
|
||||
Signature
|
||||
</DetailedInfo.ItemLabel>
|
||||
<DetailedInfo.ItemValue
|
||||
wordBreak="break-all"
|
||||
whiteSpace="normal"
|
||||
>
|
||||
{ data.signature }
|
||||
</DetailedInfo.ItemValue>
|
||||
<DetailedInfo.ItemLabel
|
||||
hint="Used to validate a User operation along with the nonce during verification"
|
||||
>
|
||||
Signature
|
||||
</DetailedInfo.ItemLabel>
|
||||
<DetailedInfo.ItemValue
|
||||
wordBreak="break-all"
|
||||
whiteSpace="normal"
|
||||
>
|
||||
{ data.signature }
|
||||
</DetailedInfo.ItemValue>
|
||||
|
||||
<DetailedInfo.ItemLabel
|
||||
hint="Anti-replay protection; also used as the salt for first-time account creation"
|
||||
>
|
||||
Nonce
|
||||
</DetailedInfo.ItemLabel>
|
||||
<DetailedInfo.ItemValue
|
||||
wordBreak="break-all"
|
||||
whiteSpace="normal"
|
||||
>
|
||||
{ data.nonce }
|
||||
</DetailedInfo.ItemValue>
|
||||
<DetailedInfo.ItemLabel
|
||||
hint="Anti-replay protection; also used as the salt for first-time account creation"
|
||||
>
|
||||
Nonce
|
||||
</DetailedInfo.ItemLabel>
|
||||
<DetailedInfo.ItemValue
|
||||
wordBreak="break-all"
|
||||
whiteSpace="normal"
|
||||
>
|
||||
{ data.nonce }
|
||||
</DetailedInfo.ItemValue>
|
||||
|
||||
<UserOpCallData data={ data }/>
|
||||
<UserOpCallData data={ data }/>
|
||||
|
||||
<UserOpDecodedCallData data={ data }/>
|
||||
</>
|
||||
) }
|
||||
<UserOpDecodedCallData data={ data }/>
|
||||
</CutLinkDetails>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
|
||||
import type { UserOp } from 'types/api/userOps';
|
||||
|
||||
import Skeleton from 'ui/shared/chakra/Skeleton';
|
||||
import { Skeleton } from 'toolkit/chakra/skeleton';
|
||||
import RawDataSnippet from 'ui/shared/RawDataSnippet';
|
||||
|
||||
// order is taken from the ERC-4337 standard
|
||||
@@ -27,7 +27,7 @@ const UserOpRaw = ({ rawData, isLoading }: Props) => {
|
||||
return res;
|
||||
}, {} as UserOp['raw']), undefined, 4);
|
||||
|
||||
return <Skeleton isLoaded={ !isLoading }><RawDataSnippet data={ text }/></Skeleton>;
|
||||
return <Skeleton loading={ isLoading }><RawDataSnippet data={ text }/></Skeleton>;
|
||||
};
|
||||
|
||||
export default UserOpRaw;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Flex, Link } from '@chakra-ui/react';
|
||||
import { Flex } from '@chakra-ui/react';
|
||||
// import type { UseQueryResult } from '@tanstack/react-query';
|
||||
import React from 'react';
|
||||
|
||||
@@ -8,6 +8,7 @@ import config from 'configs/app';
|
||||
// import type { ResourceError } from 'lib/api/resources';
|
||||
import useApiQuery from 'lib/api/useApiQuery';
|
||||
import { TX_INTERPRETATION } from 'stubs/txInterpretation';
|
||||
import { Link } from 'toolkit/chakra/link';
|
||||
import { TX_ACTIONS_BLOCK_ID } from 'ui/shared/DetailedInfo/DetailedInfoActionsWrapper';
|
||||
import UserOpEntity from 'ui/shared/entities/userOp/UserOpEntity';
|
||||
import TxInterpretation from 'ui/shared/tx/interpretation/TxInterpretation';
|
||||
|
||||
Reference in New Issue
Block a user