Commit 411cd1dc authored by isstuev's avatar isstuev

address user ops

parent d1d615e6
...@@ -77,7 +77,7 @@ import type { ...@@ -77,7 +77,7 @@ import type {
import type { TxInterpretationResponse } from 'types/api/txInterpretation'; import type { TxInterpretationResponse } from 'types/api/txInterpretation';
import type { TTxsFilters } from 'types/api/txsFilters'; import type { TTxsFilters } from 'types/api/txsFilters';
import type { TxStateChanges } from 'types/api/txStateChanges'; import type { TxStateChanges } from 'types/api/txStateChanges';
import type { UserOpsResponse, UserOp, UserOpsFilters } from 'types/api/userOps'; import type { UserOpsResponse, UserOp, UserOpsFilters, UserOpsAccount } from 'types/api/userOps';
import type { VerifiedContractsSorting } from 'types/api/verifiedContracts'; import type { VerifiedContractsSorting } from 'types/api/verifiedContracts';
import type { VisualizedContract } from 'types/api/visualization'; import type { VisualizedContract } from 'types/api/visualization';
import type { WithdrawalsResponse, WithdrawalsCounters } from 'types/api/withdrawals'; import type { WithdrawalsResponse, WithdrawalsCounters } from 'types/api/withdrawals';
...@@ -583,13 +583,17 @@ export const RESOURCES = { ...@@ -583,13 +583,17 @@ export const RESOURCES = {
// USER OPS // USER OPS
user_ops: { user_ops: {
path: '/api/v2/proxy/account-abstraction/operations', path: '/api/v2/proxy/account-abstraction/operations',
filterFields: [ 'transaction_hash' as const ], filterFields: [ 'transaction_hash' as const, 'sender' as const ],
}, },
user_op: { user_op: {
path: '/api/v2/proxy/account-abstraction/operations/:hash', path: '/api/v2/proxy/account-abstraction/operations/:hash',
pathParams: [ 'hash' as const ], pathParams: [ 'hash' as const ],
}, },
user_ops_account: {
path: '/api/v2/proxy/account-abstraction/accounts/:hash',
pathParams: [ 'hash' as const ],
},
// CONFIGS // CONFIGS
config_backend_version: { config_backend_version: {
...@@ -768,6 +772,7 @@ Q extends 'domain_events' ? EnsDomainEventsResponse : ...@@ -768,6 +772,7 @@ Q extends 'domain_events' ? EnsDomainEventsResponse :
Q extends 'domains_lookup' ? EnsDomainLookupResponse : Q extends 'domains_lookup' ? EnsDomainLookupResponse :
Q extends 'user_ops' ? UserOpsResponse : Q extends 'user_ops' ? UserOpsResponse :
Q extends 'user_op' ? UserOp : Q extends 'user_op' ? UserOp :
Q extends 'user_ops_account' ? UserOpsAccount :
never; never;
/* eslint-enable @typescript-eslint/indent */ /* eslint-enable @typescript-eslint/indent */
......
import type { UserOpsItem, UserOp } from 'types/api/userOps'; import type { UserOpsItem, UserOp, UserOpsAccount } from 'types/api/userOps';
export const USER_OPS_ITEM: UserOpsItem = { export const USER_OPS_ITEM: UserOpsItem = {
hash: '0xb94fab8f31f83001a23e20b2ce3cdcfb284c57a64b9a073e0e09c018bc701978', hash: '0xb94fab8f31f83001a23e20b2ce3cdcfb284c57a64b9a073e0e09c018bc701978',
...@@ -39,4 +39,10 @@ export const USER_OP: UserOp = { ...@@ -39,4 +39,10 @@ export const USER_OP: UserOp = {
sponsor_type: 'paymaster_sponsor', sponsor_type: 'paymaster_sponsor',
fee: '17927001792700', fee: '17927001792700',
timestamp: '1704994440', timestamp: '1704994440',
user_logs_count: 1,
user_logs_start_index: 2,
};
export const USER_OPS_ACCOUNT: UserOpsAccount = {
total_ops: 1,
}; };
...@@ -53,4 +53,9 @@ export type UserOp = { ...@@ -53,4 +53,9 @@ export type UserOp = {
export type UserOpsFilters = { export type UserOpsFilters = {
transaction_hash?: string; transaction_hash?: string;
sender?: string;
}
export type UserOpsAccount = {
total_ops: number;
} }
import { useRouter } from 'next/router';
import React from 'react';
import getQueryParamString from 'lib/router/getQueryParamString';
import { USER_OPS_ITEM } from 'stubs/userOps';
import { generateListStub } from 'stubs/utils';
import useQueryWithPages from 'ui/shared/pagination/useQueryWithPages';
import UserOpsContent from 'ui/userOps/UserOpsContent';
type Props = {
scrollRef?: React.RefObject<HTMLDivElement>;
}
const AddressUserOps = ({ scrollRef }: Props) => {
const router = useRouter();
const hash = getQueryParamString(router.query.hash);
const userOpsQuery = useQueryWithPages({
resourceName: 'user_ops',
scrollRef,
options: {
enabled: Boolean(hash),
placeholderData: generateListStub<'user_ops'>(USER_OPS_ITEM, 50, { next_page_params: {
page_token: '10355938,0x5956a847d8089e254e02e5111cad6992b99ceb9e5c2dc4343fd53002834c4dc6',
page_size: 50,
} }),
},
filters: { sender: hash },
});
return <UserOpsContent query={ userOpsQuery } showSender={ false }/>;
};
export default AddressUserOps;
...@@ -11,6 +11,7 @@ import useContractTabs from 'lib/hooks/useContractTabs'; ...@@ -11,6 +11,7 @@ import useContractTabs from 'lib/hooks/useContractTabs';
import useIsSafeAddress from 'lib/hooks/useIsSafeAddress'; import useIsSafeAddress from 'lib/hooks/useIsSafeAddress';
import getQueryParamString from 'lib/router/getQueryParamString'; import getQueryParamString from 'lib/router/getQueryParamString';
import { ADDRESS_INFO, ADDRESS_TABS_COUNTERS } from 'stubs/address'; import { ADDRESS_INFO, ADDRESS_TABS_COUNTERS } from 'stubs/address';
import { USER_OPS_ACCOUNT } from 'stubs/userOps';
import AddressBlocksValidated from 'ui/address/AddressBlocksValidated'; import AddressBlocksValidated from 'ui/address/AddressBlocksValidated';
import AddressCoinBalance from 'ui/address/AddressCoinBalance'; import AddressCoinBalance from 'ui/address/AddressCoinBalance';
import AddressContract from 'ui/address/AddressContract'; import AddressContract from 'ui/address/AddressContract';
...@@ -20,6 +21,7 @@ import AddressLogs from 'ui/address/AddressLogs'; ...@@ -20,6 +21,7 @@ import AddressLogs from 'ui/address/AddressLogs';
import AddressTokens from 'ui/address/AddressTokens'; import AddressTokens from 'ui/address/AddressTokens';
import AddressTokenTransfers from 'ui/address/AddressTokenTransfers'; import AddressTokenTransfers from 'ui/address/AddressTokenTransfers';
import AddressTxs from 'ui/address/AddressTxs'; import AddressTxs from 'ui/address/AddressTxs';
import AddressUserOps from 'ui/address/AddressUserOps';
import AddressWithdrawals from 'ui/address/AddressWithdrawals'; import AddressWithdrawals from 'ui/address/AddressWithdrawals';
import AddressFavoriteButton from 'ui/address/details/AddressFavoriteButton'; import AddressFavoriteButton from 'ui/address/details/AddressFavoriteButton';
import AddressQrCode from 'ui/address/details/AddressQrCode'; import AddressQrCode from 'ui/address/details/AddressQrCode';
...@@ -62,6 +64,14 @@ const AddressPageContent = () => { ...@@ -62,6 +64,14 @@ const AddressPageContent = () => {
}, },
}); });
const userOpsAccountQuery = useApiQuery('user_ops_account', {
pathParams: { hash },
queryOptions: {
enabled: Boolean(hash),
placeholderData: USER_OPS_ACCOUNT,
},
});
const isSafeAddress = useIsSafeAddress(!addressQuery.isPlaceholderData && addressQuery.data?.is_contract ? hash : undefined); const isSafeAddress = useIsSafeAddress(!addressQuery.isPlaceholderData && addressQuery.data?.is_contract ? hash : undefined);
const contractTabs = useContractTabs(addressQuery.data); const contractTabs = useContractTabs(addressQuery.data);
...@@ -74,6 +84,14 @@ const AddressPageContent = () => { ...@@ -74,6 +84,14 @@ const AddressPageContent = () => {
count: addressTabsCountersQuery.data?.transactions_count, count: addressTabsCountersQuery.data?.transactions_count,
component: <AddressTxs scrollRef={ tabsScrollRef }/>, component: <AddressTxs scrollRef={ tabsScrollRef }/>,
}, },
config.features.userOps.isEnabled && Boolean(userOpsAccountQuery.data?.total_ops) ?
{
id: 'user_ops',
title: 'User operations',
count: userOpsAccountQuery.data?.total_ops,
component: <AddressUserOps/>,
} :
undefined,
config.features.beaconChain.isEnabled && addressTabsCountersQuery.data?.withdrawals_count ? config.features.beaconChain.isEnabled && addressTabsCountersQuery.data?.withdrawals_count ?
{ {
id: 'withdrawals', id: 'withdrawals',
...@@ -140,7 +158,7 @@ const AddressPageContent = () => { ...@@ -140,7 +158,7 @@ const AddressPageContent = () => {
subTabs: contractTabs.map(tab => tab.id), subTabs: contractTabs.map(tab => tab.id),
} : undefined, } : undefined,
].filter(Boolean); ].filter(Boolean);
}, [ addressQuery.data, contractTabs, addressTabsCountersQuery.data ]); }, [ addressQuery.data, contractTabs, addressTabsCountersQuery.data, userOpsAccountQuery.data ]);
const tags = ( const tags = (
<EntityTags <EntityTags
...@@ -151,6 +169,7 @@ const AddressPageContent = () => { ...@@ -151,6 +169,7 @@ const AddressPageContent = () => {
addressQuery.data?.implementation_address ? { label: 'proxy', display_name: 'Proxy' } : undefined, addressQuery.data?.implementation_address ? { label: 'proxy', display_name: 'Proxy' } : undefined,
addressQuery.data?.token ? { label: 'token', display_name: 'Token' } : undefined, addressQuery.data?.token ? { label: 'token', display_name: 'Token' } : undefined,
isSafeAddress ? { label: 'safe', display_name: 'Multisig: Safe' } : undefined, isSafeAddress ? { label: 'safe', display_name: 'Multisig: Safe' } : undefined,
userOpsAccountQuery.data?.total_ops ? { label: 'user_ops_acc', display_name: 'Smart contract wallet' } : undefined,
] } ] }
/> />
); );
...@@ -222,7 +241,10 @@ const AddressPageContent = () => { ...@@ -222,7 +241,10 @@ const AddressPageContent = () => {
<AddressDetails addressQuery={ addressQuery } scrollRef={ tabsScrollRef }/> <AddressDetails addressQuery={ addressQuery } scrollRef={ tabsScrollRef }/>
{ /* should stay before tabs to scroll up with pagination */ } { /* should stay before tabs to scroll up with pagination */ }
<Box ref={ tabsScrollRef }></Box> <Box ref={ tabsScrollRef }></Box>
{ (addressQuery.isPlaceholderData || addressTabsCountersQuery.isPlaceholderData) ? <TabsSkeleton tabs={ tabs }/> : content } { (addressQuery.isPlaceholderData || addressTabsCountersQuery.isPlaceholderData || userOpsAccountQuery.isPlaceholderData) ?
<TabsSkeleton tabs={ tabs }/> :
content
}
</> </>
); );
}; };
......
import { Hide, Show } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import { USER_OPS_ITEM } from 'stubs/userOps'; import { USER_OPS_ITEM } from 'stubs/userOps';
import { generateListStub } from 'stubs/utils'; import { generateListStub } from 'stubs/utils';
import ActionBar from 'ui/shared/ActionBar';
import DataListDisplay from 'ui/shared/DataListDisplay';
import PageTitle from 'ui/shared/Page/PageTitle'; import PageTitle from 'ui/shared/Page/PageTitle';
import Pagination from 'ui/shared/pagination/Pagination';
import useQueryWithPages from 'ui/shared/pagination/useQueryWithPages'; import useQueryWithPages from 'ui/shared/pagination/useQueryWithPages';
import UserOpsListItem from 'ui/userOps/UserOpsListItem'; import UserOpsContent from 'ui/userOps/UserOpsContent';
import UserOpsTable from 'ui/userOps/UserOpsTable';
const UserOps = () => { const UserOps = () => {
const { data, isError, isPlaceholderData, pagination } = useQueryWithPages({ const query = useQueryWithPages({
resourceName: 'user_ops', resourceName: 'user_ops',
options: { options: {
placeholderData: generateListStub<'user_ops'>(USER_OPS_ITEM, 50, { next_page_params: { placeholderData: generateListStub<'user_ops'>(USER_OPS_ITEM, 50, { next_page_params: {
...@@ -22,39 +17,10 @@ const UserOps = () => { ...@@ -22,39 +17,10 @@ const UserOps = () => {
}, },
}); });
const content = data?.items ? (
<>
<Show below="lg" ssr={ false }>
{ data.items.map(((item, index) => (
<UserOpsListItem
key={ item.hash + (isPlaceholderData ? String(index) : '') }
item={ item }
isLoading={ isPlaceholderData }
/>
))) }
</Show>
<Hide below="lg" ssr={ false }>
<UserOpsTable items={ data.items } top={ pagination.isVisible ? 80 : 0 } isLoading={ isPlaceholderData }/>
</Hide>
</>
) : null;
const actionBar = pagination.isVisible ? (
<ActionBar mt={ -6 } alignItems="center">
<Pagination ml="auto" { ...pagination }/>
</ActionBar>
) : null;
return ( return (
<> <>
<PageTitle title="User operations" withTextAd/> <PageTitle title="User operations" withTextAd/>
<DataListDisplay <UserOpsContent query={ query }/>
isError={ isError }
items={ data?.items }
emptyText="There are no user operations."
content={ content }
actionBar={ actionBar }
/>
</> </>
); );
}; };
......
import { Hide, Show } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import { SECOND } from 'lib/consts'; import { SECOND } from 'lib/consts';
import { USER_OPS_ITEM } from 'stubs/userOps'; import { USER_OPS_ITEM } from 'stubs/userOps';
import { generateListStub } from 'stubs/utils'; import { generateListStub } from 'stubs/utils';
import ActionBar from 'ui/shared/ActionBar';
import DataFetchAlert from 'ui/shared/DataFetchAlert';
import DataListDisplay from 'ui/shared/DataListDisplay';
import Pagination from 'ui/shared/pagination/Pagination';
import useQueryWithPages from 'ui/shared/pagination/useQueryWithPages'; import useQueryWithPages from 'ui/shared/pagination/useQueryWithPages';
import TxPendingAlert from 'ui/tx/TxPendingAlert'; import TxPendingAlert from 'ui/tx/TxPendingAlert';
import TxSocketAlert from 'ui/tx/TxSocketAlert'; import TxSocketAlert from 'ui/tx/TxSocketAlert';
import useFetchTxInfo from 'ui/tx/useFetchTxInfo'; import useFetchTxInfo from 'ui/tx/useFetchTxInfo';
import UserOpsListItem from 'ui/userOps/UserOpsListItem'; import UserOpsContent from 'ui/userOps/UserOpsContent';
import UserOpsTable from 'ui/userOps/UserOpsTable';
const TxTokenTransfer = () => { const TxUserOps = () => {
const txsInfo = useFetchTxInfo({ updateDelay: 5 * SECOND }); const txsInfo = useFetchTxInfo({ updateDelay: 5 * SECOND });
const userOpsQuery = useQueryWithPages({ const userOpsQuery = useQueryWithPages({
...@@ -32,42 +26,7 @@ const TxTokenTransfer = () => { ...@@ -32,42 +26,7 @@ const TxTokenTransfer = () => {
return txsInfo.socketStatus ? <TxSocketAlert status={ txsInfo.socketStatus }/> : <TxPendingAlert/>; return txsInfo.socketStatus ? <TxSocketAlert status={ txsInfo.socketStatus }/> : <TxPendingAlert/>;
} }
if (txsInfo.isError || userOpsQuery.isError) { return <UserOpsContent query={ userOpsQuery } showTx={ false }/>;
return <DataFetchAlert/>;
}
const content = userOpsQuery.data?.items ? (
<>
<Hide below="lg" ssr={ false }>
<UserOpsTable items={ userOpsQuery.data?.items } top={ userOpsQuery.pagination.isVisible ? 0 : 80 } isLoading={ userOpsQuery.isPlaceholderData }/>
</Hide>
<Show below="lg" ssr={ false }>
{ userOpsQuery.data.items.map(((item, index) => (
<UserOpsListItem
key={ item.hash + (userOpsQuery.isPlaceholderData ? String(index) : '') }
item={ item }
isLoading={ userOpsQuery.isPlaceholderData }
/>
))) }
</Show>
</>
) : null;
const actionBar = userOpsQuery.pagination.isVisible ? (
<ActionBar mt={ -6 } alignItems="center">
<Pagination ml="auto" { ...userOpsQuery.pagination }/>
</ActionBar>
) : null;
return (
<DataListDisplay
isError={ txsInfo.isError || userOpsQuery.isError }
items={ userOpsQuery.data?.items }
emptyText="There are no user operations."
content={ content }
actionBar={ actionBar }
/>
);
}; };
export default TxTokenTransfer; export default TxUserOps;
import { Hide, Show } from '@chakra-ui/react';
import React from 'react';
import ActionBar from 'ui/shared/ActionBar';
import DataFetchAlert from 'ui/shared/DataFetchAlert';
import DataListDisplay from 'ui/shared/DataListDisplay';
import Pagination from 'ui/shared/pagination/Pagination';
import type { QueryWithPagesResult } from 'ui/shared/pagination/useQueryWithPages';
import UserOpsListItem from 'ui/userOps/UserOpsListItem';
import UserOpsTable from 'ui/userOps/UserOpsTable';
type Props = {
query: QueryWithPagesResult<'user_ops'>;
showTx?: boolean;
showSender?: boolean;
};
const UserOpsContent = ({ query, showTx = true, showSender = true }: Props) => {
if (query.isError) {
return <DataFetchAlert/>;
}
const content = query.data?.items ? (
<>
<Hide below="lg" ssr={ false }>
<UserOpsTable
items={ query.data.items }
top={ query.pagination.isVisible ? 0 : 80 }
isLoading={ query.isPlaceholderData }
showTx={ showTx }
showSender={ showSender }
/>
</Hide>
<Show below="lg" ssr={ false }>
{ query.data.items.map(((item, index) => (
<UserOpsListItem
key={ item.hash + (query.isPlaceholderData ? String(index) : '') }
item={ item }
isLoading={ query.isPlaceholderData }
showTx={ showTx }
showSender={ showSender }
/>
))) }
</Show>
</>
) : null;
const actionBar = query.pagination.isVisible ? (
<ActionBar mt={ -6 } alignItems="center">
<Pagination ml="auto" { ...query.pagination }/>
</ActionBar>
) : null;
return (
<DataListDisplay
isError={ query.isError }
items={ query.data?.items }
emptyText="There are no user operations."
content={ content }
actionBar={ actionBar }
/>
);
};
export default UserOpsContent;
...@@ -16,9 +16,11 @@ import UserOpStatus from 'ui/shared/userOps/UserOpStatus'; ...@@ -16,9 +16,11 @@ import UserOpStatus from 'ui/shared/userOps/UserOpStatus';
type Props = { type Props = {
item: UserOpsItem; item: UserOpsItem;
isLoading?: boolean; isLoading?: boolean;
showTx: boolean;
showSender: boolean;
}; };
const UserOpsListItem = ({ item, isLoading }: Props) => { const UserOpsListItem = ({ item, isLoading, showTx, showSender }: Props) => {
// format will be fixed on the back-end // format will be fixed on the back-end
const timeAgo = dayjs(Number(item.timestamp) * 1000).fromNow(); const timeAgo = dayjs(Number(item.timestamp) * 1000).fromNow();
...@@ -40,6 +42,8 @@ const UserOpsListItem = ({ item, isLoading }: Props) => { ...@@ -40,6 +42,8 @@ const UserOpsListItem = ({ item, isLoading }: Props) => {
<UserOpStatus status={ item.status } isLoading={ isLoading }/> <UserOpStatus status={ item.status } isLoading={ isLoading }/>
</ListItemMobileGrid.Value> </ListItemMobileGrid.Value>
{ showSender && (
<>
<ListItemMobileGrid.Label isLoading={ isLoading }>Sender</ListItemMobileGrid.Label> <ListItemMobileGrid.Label isLoading={ isLoading }>Sender</ListItemMobileGrid.Label>
<ListItemMobileGrid.Value> <ListItemMobileGrid.Value>
<UserOpsAddress <UserOpsAddress
...@@ -47,7 +51,11 @@ const UserOpsListItem = ({ item, isLoading }: Props) => { ...@@ -47,7 +51,11 @@ const UserOpsListItem = ({ item, isLoading }: Props) => {
isLoading={ isLoading } isLoading={ isLoading }
/> />
</ListItemMobileGrid.Value> </ListItemMobileGrid.Value>
</>
) }
{ showTx && (
<>
<ListItemMobileGrid.Label isLoading={ isLoading }>Tx hash</ListItemMobileGrid.Label> <ListItemMobileGrid.Label isLoading={ isLoading }>Tx hash</ListItemMobileGrid.Label>
<ListItemMobileGrid.Value> <ListItemMobileGrid.Value>
<TxEntity <TxEntity
...@@ -56,6 +64,8 @@ const UserOpsListItem = ({ item, isLoading }: Props) => { ...@@ -56,6 +64,8 @@ const UserOpsListItem = ({ item, isLoading }: Props) => {
noIcon noIcon
/> />
</ListItemMobileGrid.Value> </ListItemMobileGrid.Value>
</>
) }
<ListItemMobileGrid.Label isLoading={ isLoading }>Block</ListItemMobileGrid.Label> <ListItemMobileGrid.Label isLoading={ isLoading }>Block</ListItemMobileGrid.Label>
<ListItemMobileGrid.Value> <ListItemMobileGrid.Value>
......
...@@ -12,9 +12,11 @@ import UserOpsTableItem from './UserOpsTableItem'; ...@@ -12,9 +12,11 @@ import UserOpsTableItem from './UserOpsTableItem';
items: Array<UserOpsItem>; items: Array<UserOpsItem>;
isLoading?: boolean; isLoading?: boolean;
top: number; top: number;
showTx: boolean;
showSender: boolean;
}; };
const UserOpsTable = ({ items, isLoading, top }: Props) => { const UserOpsTable = ({ items, isLoading, top, showTx, showSender }: Props) => {
return ( return (
<Table variant="simple" size="sm"> <Table variant="simple" size="sm">
<Thead top={ top }> <Thead top={ top }>
...@@ -22,15 +24,21 @@ const UserOpsTable = ({ items, isLoading, top }: Props) => { ...@@ -22,15 +24,21 @@ const UserOpsTable = ({ items, isLoading, top }: Props) => {
<Th w="60%">User op hash</Th> <Th w="60%">User op hash</Th>
<Th w="110px">Age</Th> <Th w="110px">Age</Th>
<Th w="140px">Status</Th> <Th w="140px">Status</Th>
<Th w="160px">Sender</Th> { showSender && <Th w="160px">Sender</Th> }
<Th w="160px">Tx hash</Th> { showTx && <Th w="160px">Tx hash</Th> }
<Th w="40%">Block</Th> <Th w="40%">Block</Th>
{ !config.UI.views.tx.hiddenFields?.tx_fee && <Th w="120px" isNumeric>{ `Fee ${ config.chain.currency.symbol }` }</Th> } { !config.UI.views.tx.hiddenFields?.tx_fee && <Th w="120px" isNumeric>{ `Fee ${ config.chain.currency.symbol }` }</Th> }
</Tr> </Tr>
</Thead> </Thead>
<Tbody> <Tbody>
{ items.map((item, index) => ( { items.map((item, index) => (
<UserOpsTableItem key={ (isLoading ? String(index) : '') } item={ item } isLoading={ isLoading }/> <UserOpsTableItem
key={ (isLoading ? String(index) : '') }
item={ item }
isLoading={ isLoading }
showSender={ showSender }
showTx={ showTx }
/>
)) } )) }
</Tbody> </Tbody>
</Table> </Table>
......
...@@ -15,9 +15,11 @@ import UserOpStatus from 'ui/shared/userOps/UserOpStatus'; ...@@ -15,9 +15,11 @@ import UserOpStatus from 'ui/shared/userOps/UserOpStatus';
type Props = { type Props = {
item: UserOpsItem; item: UserOpsItem;
isLoading?: boolean; isLoading?: boolean;
showTx: boolean;
showSender: boolean;
}; };
const WithdrawalsTableItem = ({ item, isLoading }: Props) => { const UserOpsTableItem = ({ item, isLoading, showTx, showSender }: Props) => {
// will be fixed on the back-end // will be fixed on the back-end
const timeAgo = dayjs(Number(item.timestamp) * 1000).fromNow(); const timeAgo = dayjs(Number(item.timestamp) * 1000).fromNow();
...@@ -32,6 +34,7 @@ const WithdrawalsTableItem = ({ item, isLoading }: Props) => { ...@@ -32,6 +34,7 @@ const WithdrawalsTableItem = ({ item, isLoading }: Props) => {
<Td verticalAlign="middle"> <Td verticalAlign="middle">
<UserOpStatus status={ item.status } isLoading={ isLoading }/> <UserOpStatus status={ item.status } isLoading={ isLoading }/>
</Td> </Td>
{ showSender && (
<Td verticalAlign="middle"> <Td verticalAlign="middle">
<UserOpsAddress <UserOpsAddress
address={ item.address } address={ item.address }
...@@ -39,6 +42,8 @@ const WithdrawalsTableItem = ({ item, isLoading }: Props) => { ...@@ -39,6 +42,8 @@ const WithdrawalsTableItem = ({ item, isLoading }: Props) => {
truncation="constant" truncation="constant"
/> />
</Td> </Td>
) }
{ showTx && (
<Td verticalAlign="middle"> <Td verticalAlign="middle">
<TxEntity <TxEntity
hash={ item.transaction_hash } hash={ item.transaction_hash }
...@@ -47,6 +52,7 @@ const WithdrawalsTableItem = ({ item, isLoading }: Props) => { ...@@ -47,6 +52,7 @@ const WithdrawalsTableItem = ({ item, isLoading }: Props) => {
noIcon noIcon
/> />
</Td> </Td>
) }
<Td verticalAlign="middle"> <Td verticalAlign="middle">
<BlockEntity <BlockEntity
number={ item.block_number } number={ item.block_number }
...@@ -65,4 +71,4 @@ const WithdrawalsTableItem = ({ item, isLoading }: Props) => { ...@@ -65,4 +71,4 @@ const WithdrawalsTableItem = ({ item, isLoading }: Props) => {
); );
}; };
export default WithdrawalsTableItem; export default UserOpsTableItem;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment