Commit f00d3b38 authored by isstuev's avatar isstuev

token transfers and call data

parent a6ab591b
...@@ -47,4 +47,6 @@ export type UserOp = { ...@@ -47,4 +47,6 @@ export type UserOp = {
signature: string; signature: string;
nonce: string; nonce: string;
call_data: string; call_data: string;
user_logs_start_index: number;
user_logs_count: number;
} }
import { inRange } from 'lodash';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import React from 'react'; import React from 'react';
import type { TokenTransfer } from 'types/api/tokenTransfer';
import type { RoutedTab } from 'ui/shared/Tabs/types'; import type { RoutedTab } from 'ui/shared/Tabs/types';
import useApiQuery from 'lib/api/useApiQuery'; import useApiQuery from 'lib/api/useApiQuery';
...@@ -13,6 +15,8 @@ import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic'; ...@@ -13,6 +15,8 @@ import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic';
import PageTitle from 'ui/shared/Page/PageTitle'; import PageTitle from 'ui/shared/Page/PageTitle';
import RoutedTabs from 'ui/shared/Tabs/RoutedTabs'; import RoutedTabs from 'ui/shared/Tabs/RoutedTabs';
import TabsSkeleton from 'ui/shared/Tabs/TabsSkeleton'; import TabsSkeleton from 'ui/shared/Tabs/TabsSkeleton';
import TxTokenTransfer from 'ui/tx/TxTokenTransfer';
import UserOpCallData from 'ui/userOp/UserOpCallData';
import UserOpDetails from 'ui/userOp/UserOpDetails'; import UserOpDetails from 'ui/userOp/UserOpDetails';
const TAB_LIST_PROPS = { const TAB_LIST_PROPS = {
...@@ -35,14 +39,28 @@ const BlockPageContent = () => { ...@@ -35,14 +39,28 @@ const BlockPageContent = () => {
}, },
}); });
const filterTokenTransfersByLogIndex = React.useCallback((tt: TokenTransfer) => {
if (!userOpQuery.data) {
return true;
} else {
if (inRange(Number(tt.log_index), userOpQuery.data.user_logs_start_index, userOpQuery.data.user_logs_start_index + userOpQuery.data.user_logs_count)) {
return true;
}
return false;
}
}, [ userOpQuery.data ]);
const tabs: Array<RoutedTab> = React.useMemo(() => ([ const tabs: Array<RoutedTab> = React.useMemo(() => ([
{ id: 'index', title: 'Details', component: <UserOpDetails query={ userOpQuery }/> }, { id: 'index', title: 'Details', component: <UserOpDetails query={ userOpQuery }/> },
{ id: 'token_transfers', title: 'Token transfers', component: null }, {
// { id: 'token_transfers', title: 'Token transfers', component: <UserOpTokenTransfers txHash={ userOpQuery.data?.transaction_hash }/> }, id: 'token_transfers',
// { id: 'call_data', title: 'Call data', component: <UserOpCallData callData={ userOpQuery.data?.call_data }/> } title: 'Token transfers',
component: <TxTokenTransfer txHash={ userOpQuery.data?.transaction_hash } tokenTransferFilter={ filterTokenTransfersByLogIndex }/>,
},
{ id: 'call_data', title: 'Call data', component: <UserOpCallData rawCallData={ userOpQuery.data?.call_data }/> },
// { id: 'logs', title: 'Logs', component: <UserOpLogs txHash={ userOpQuery.data?.transaction_hash }/> } // { id: 'logs', title: 'Logs', component: <UserOpLogs txHash={ userOpQuery.data?.transaction_hash }/> }
// { id: 'raw', title: 'Raw', component: <UserOpRaw txHash={ userOpQuery.data?.transaction_hash }/> } // { id: 'raw', title: 'Raw', component: <UserOpRaw txHash={ userOpQuery.data?.transaction_hash }/> }
].filter(Boolean)), [ userOpQuery ]); ].filter(Boolean)), [ userOpQuery, filterTokenTransfersByLogIndex ]);
if (!hash) { if (!hash) {
throw new Error('User operation not found', { cause: { status: 404 } }); throw new Error('User operation not found', { cause: { status: 404 } });
......
...@@ -3,6 +3,7 @@ import { useRouter } from 'next/router'; ...@@ -3,6 +3,7 @@ import { useRouter } from 'next/router';
import React from 'react'; import React from 'react';
import type { TokenType } from 'types/api/token'; import type { TokenType } from 'types/api/token';
import type { TokenTransfer } from 'types/api/tokenTransfer';
import { SECOND } from 'lib/consts'; import { SECOND } from 'lib/consts';
import getFilterValuesFromQuery from 'lib/getFilterValuesFromQuery'; import getFilterValuesFromQuery from 'lib/getFilterValuesFromQuery';
...@@ -23,8 +24,13 @@ import useFetchTxInfo from 'ui/tx/useFetchTxInfo'; ...@@ -23,8 +24,13 @@ import useFetchTxInfo from 'ui/tx/useFetchTxInfo';
const getTokenFilterValue = (getFilterValuesFromQuery<TokenType>).bind(null, TOKEN_TYPE_IDS); const getTokenFilterValue = (getFilterValuesFromQuery<TokenType>).bind(null, TOKEN_TYPE_IDS);
const TxTokenTransfer = () => { type Props = {
const txsInfo = useFetchTxInfo({ updateDelay: 5 * SECOND }); txHash?: string;
tokenTransferFilter?: (tt: TokenTransfer) => boolean;
}
const TxTokenTransfer = ({ txHash, tokenTransferFilter }: Props) => {
const txsInfo = useFetchTxInfo({ updateDelay: 5 * SECOND, txHash });
const router = useRouter(); const router = useRouter();
...@@ -56,13 +62,23 @@ const TxTokenTransfer = () => { ...@@ -56,13 +62,23 @@ const TxTokenTransfer = () => {
const numActiveFilters = typeFilter.length; const numActiveFilters = typeFilter.length;
const isActionBarHidden = !numActiveFilters && !tokenTransferQuery.data?.items.length; const isActionBarHidden = !numActiveFilters && !tokenTransferQuery.data?.items.length;
let items: Array<TokenTransfer> = [];
if (tokenTransferQuery.data?.items) {
if (tokenTransferQuery.isPlaceholderData) {
items = tokenTransferQuery.data?.items;
} else {
items = tokenTransferFilter ? tokenTransferQuery.data.items.filter(tokenTransferFilter) : tokenTransferQuery.data.items;
}
}
const content = tokenTransferQuery.data?.items ? ( const content = tokenTransferQuery.data?.items ? (
<> <>
<Hide below="lg" ssr={ false }> <Hide below="lg" ssr={ false }>
<TokenTransferTable data={ tokenTransferQuery.data?.items } top={ isActionBarHidden ? 0 : 80 } isLoading={ tokenTransferQuery.isPlaceholderData }/> <TokenTransferTable data={ items } top={ isActionBarHidden ? 0 : 80 } isLoading={ tokenTransferQuery.isPlaceholderData }/>
</Hide> </Hide>
<Show below="lg" ssr={ false }> <Show below="lg" ssr={ false }>
<TokenTransferList data={ tokenTransferQuery.data?.items } isLoading={ tokenTransferQuery.isPlaceholderData }/> <TokenTransferList data={ items } isLoading={ tokenTransferQuery.isPlaceholderData }/>
</Show> </Show>
</> </>
) : null; ) : null;
...@@ -82,7 +98,7 @@ const TxTokenTransfer = () => { ...@@ -82,7 +98,7 @@ const TxTokenTransfer = () => {
return ( return (
<DataListDisplay <DataListDisplay
isError={ txsInfo.isError || tokenTransferQuery.isError } isError={ txsInfo.isError || tokenTransferQuery.isError }
items={ tokenTransferQuery.data?.items } items={ items }
emptyText="There are no token transfers." emptyText="There are no token transfers."
filterProps={{ filterProps={{
emptyFilteredText: `Couldn${ apos }t find any token transfer that matches your query.`, emptyFilteredText: `Couldn${ apos }t find any token transfer that matches your query.`,
......
...@@ -18,17 +18,18 @@ import { TX, TX_ZKEVM_L2 } from 'stubs/tx'; ...@@ -18,17 +18,18 @@ import { TX, TX_ZKEVM_L2 } from 'stubs/tx';
interface Params { interface Params {
onTxStatusUpdate?: () => void; onTxStatusUpdate?: () => void;
updateDelay?: number; updateDelay?: number;
txHash?: string;
} }
type ReturnType = UseQueryResult<Transaction, ResourceError<{ status: number }>> & { type ReturnType = UseQueryResult<Transaction, ResourceError<{ status: number }>> & {
socketStatus: 'close' | 'error' | undefined; socketStatus: 'close' | 'error' | undefined;
} }
export default function useFetchTxInfo({ onTxStatusUpdate, updateDelay }: Params | undefined = {}): ReturnType { export default function useFetchTxInfo({ onTxStatusUpdate, updateDelay, txHash }: Params | undefined = {}): ReturnType {
const router = useRouter(); const router = useRouter();
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const [ socketStatus, setSocketStatus ] = React.useState<'close' | 'error'>(); const [ socketStatus, setSocketStatus ] = React.useState<'close' | 'error'>();
const hash = getQueryParamString(router.query.hash); const hash = txHash || getQueryParamString(router.query.hash);
const queryResult = useApiQuery<'tx', { status: number }>('tx', { const queryResult = useApiQuery<'tx', { status: number }>('tx', {
pathParams: { hash }, pathParams: { hash },
......
import React from 'react';
import RawInputData from 'ui/shared/RawInputData';
// decoded calldata will be added later
type Props = {
rawCallData?: string;
}
const UserOpCallData = ({ rawCallData }: Props) => {
if (!rawCallData) {
return null;
}
return <RawInputData hex={ rawCallData }/>;
};
export default UserOpCallData;
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