Commit eef534bb authored by tom goriunov's avatar tom goriunov Committed by GitHub

Update API Endpoint for fetching `has_methods_*` and `has_custom_meth… (#1842)

* Update API Endpoint for fetching `has_methods_*` and `has_custom_methods_*` fields

Fixes #1821

* don't load address txs when navigating to contract tab

* fix test
parent ee5467fa
import { useRouter } from 'next/router';
import React from 'react';
import type { Address } from 'types/api/address';
import useApiQuery from 'lib/api/useApiQuery';
import getQueryParamString from 'lib/router/getQueryParamString';
import useSocketChannel from 'lib/socket/useSocketChannel';
import * as stubs from 'stubs/contract';
import ContractCode from 'ui/address/contract/ContractCode';
import ContractRead from 'ui/address/contract/ContractRead';
import ContractWrite from 'ui/address/contract/ContractWrite';
export default function useContractTabs(data: Address | undefined) {
const CONTRACT_TAB_IDS = [
'contract_code',
'read_contract',
'read_proxy',
'read_custom_methods',
'write_contract',
'write_proxy',
'write_custom_methods',
] as const;
interface ContractTab {
id: typeof CONTRACT_TAB_IDS[number];
title: string;
component: JSX.Element;
}
interface ReturnType {
tabs: Array<ContractTab>;
isLoading: boolean;
}
export default function useContractTabs(data: Address | undefined, isPlaceholderData: boolean): ReturnType {
const [ isQueryEnabled, setIsQueryEnabled ] = React.useState(false);
const router = useRouter();
const tab = getQueryParamString(router.query.tab);
const isEnabled = Boolean(data?.hash) && !isPlaceholderData && CONTRACT_TAB_IDS.concat('contract' as never).includes(tab);
const enableQuery = React.useCallback(() => {
setIsQueryEnabled(true);
}, []);
const contractQuery = useApiQuery('contract', {
pathParams: { hash: data?.hash },
queryOptions: {
enabled: isEnabled && isQueryEnabled,
refetchOnMount: false,
placeholderData: data?.is_verified ? stubs.CONTRACT_CODE_VERIFIED : stubs.CONTRACT_CODE_UNVERIFIED,
},
});
const channel = useSocketChannel({
topic: `addresses:${ data?.hash?.toLowerCase() }`,
isDisabled: !isEnabled,
onJoin: enableQuery,
onSocketError: enableQuery,
});
return React.useMemo(() => {
return [
{ id: 'contact_code', title: 'Code', component: <ContractCode addressHash={ data?.hash }/> },
// this is not implemented in api yet
// data?.has_decompiled_code ?
// { id: 'contact_decompiled_code', title: 'Decompiled code', component: <div>Decompiled code</div> } :
// undefined,
data?.has_methods_read ?
{ id: 'read_contract', title: 'Read contract', component: <ContractRead/> } :
return {
tabs: [
{
id: 'contract_code' as const,
title: 'Code',
component: <ContractCode contractQuery={ contractQuery } channel={ channel } addressHash={ data?.hash }/>,
},
contractQuery.data?.has_methods_read ?
{ id: 'read_contract' as const, title: 'Read contract', component: <ContractRead isLoading={ contractQuery.isPlaceholderData }/> } :
undefined,
data?.has_methods_read_proxy ?
{ id: 'read_proxy', title: 'Read proxy', component: <ContractRead/> } :
contractQuery.data?.has_methods_read_proxy ?
{ id: 'read_proxy' as const, title: 'Read proxy', component: <ContractRead isLoading={ contractQuery.isPlaceholderData }/> } :
undefined,
data?.has_custom_methods_read ?
{ id: 'read_custom_methods', title: 'Read custom', component: <ContractRead/> } :
contractQuery.data?.has_custom_methods_read ?
{ id: 'read_custom_methods' as const, title: 'Read custom', component: <ContractRead isLoading={ contractQuery.isPlaceholderData }/> } :
undefined,
data?.has_methods_write ?
{ id: 'write_contract', title: 'Write contract', component: <ContractWrite/> } :
contractQuery.data?.has_methods_write ?
{ id: 'write_contract' as const, title: 'Write contract', component: <ContractWrite isLoading={ contractQuery.isPlaceholderData }/> } :
undefined,
data?.has_methods_write_proxy ?
{ id: 'write_proxy', title: 'Write proxy', component: <ContractWrite/> } :
contractQuery.data?.has_methods_write_proxy ?
{ id: 'write_proxy' as const, title: 'Write proxy', component: <ContractWrite isLoading={ contractQuery.isPlaceholderData }/> } :
undefined,
data?.has_custom_methods_write ?
{ id: 'write_custom_methods', title: 'Write custom', component: <ContractWrite/> } :
contractQuery.data?.has_custom_methods_write ?
{ id: 'write_custom_methods' as const, title: 'Write custom', component: <ContractWrite isLoading={ contractQuery.isPlaceholderData }/> } :
undefined,
].filter(Boolean);
}, [ data ]);
].filter(Boolean),
isLoading: contractQuery.isPlaceholderData,
};
}, [ contractQuery, channel, data?.hash ]);
}
......@@ -59,14 +59,8 @@ export const token: Address = {
creator_address_hash: '0x34A9c688512ebdB575e82C50c9803F6ba2916E72',
exchange_rate: null,
implementation_address: null,
has_custom_methods_read: false,
has_custom_methods_write: false,
has_decompiled_code: false,
has_logs: false,
has_methods_read: false,
has_methods_read_proxy: false,
has_methods_write: false,
has_methods_write_proxy: false,
has_token_transfers: true,
has_tokens: true,
has_validated_blocks: false,
......@@ -79,14 +73,8 @@ export const contract: Address = {
creation_tx_hash: '0xf2aff6501b632604c39978b47d309813d8a1bcca721864bbe86abf59704f195e',
creator_address_hash: '0x803ad3F50b9e1fF68615e8B053A186e1be288943',
exchange_rate: '0.04311',
has_custom_methods_read: false,
has_custom_methods_write: false,
has_decompiled_code: false,
has_logs: true,
has_methods_read: true,
has_methods_read_proxy: true,
has_methods_write: true,
has_methods_write_proxy: true,
has_token_transfers: false,
has_tokens: false,
has_validated_blocks: false,
......@@ -110,14 +98,8 @@ export const validator: Address = {
creation_tx_hash: null,
creator_address_hash: null,
exchange_rate: '0.00432018',
has_custom_methods_read: false,
has_custom_methods_write: false,
has_decompiled_code: false,
has_logs: false,
has_methods_read: false,
has_methods_read_proxy: false,
has_methods_write: false,
has_methods_write_proxy: false,
has_token_transfers: false,
has_tokens: false,
has_validated_blocks: true,
......
/* eslint-disable max-len */
import type { SmartContract } from 'types/api/contract';
export const verified: Partial<SmartContract> = {
export const verified: SmartContract = {
abi: [ { anonymous: false, inputs: [ { indexed: true, internalType: 'address', name: 'src', type: 'address' }, { indexed: true, internalType: 'address', name: 'guy', type: 'address' }, { indexed: false, internalType: 'uint256', name: 'wad', type: 'uint256' } ], name: 'Approval', type: 'event' } ],
can_be_visualized_via_sol2uml: true,
compiler_version: 'v0.5.16+commit.9c3226ce',
......@@ -32,9 +32,26 @@ export const verified: Partial<SmartContract> = {
],
language: 'solidity',
license_type: 'gnu_gpl_v3',
has_methods_read: true,
has_methods_read_proxy: false,
has_methods_write: true,
has_methods_write_proxy: false,
has_custom_methods_read: false,
has_custom_methods_write: false,
is_self_destructed: false,
is_verified_via_eth_bytecode_db: null,
is_changed_bytecode: null,
is_verified_via_sourcify: null,
is_fully_verified: null,
is_partially_verified: null,
sourcify_repo_url: null,
file_path: '',
additional_sources: [],
verified_twin_address_hash: null,
minimal_proxy_address_hash: null,
};
export const withMultiplePaths: Partial<SmartContract> = {
export const withMultiplePaths: SmartContract = {
...verified,
file_path: './simple_storage.sol',
additional_sources: [
......@@ -45,7 +62,7 @@ export const withMultiplePaths: Partial<SmartContract> = {
],
};
export const verifiedViaSourcify: Partial<SmartContract> = {
export const verifiedViaSourcify: SmartContract = {
...verified,
is_verified_via_sourcify: true,
is_fully_verified: false,
......@@ -53,36 +70,67 @@ export const verifiedViaSourcify: Partial<SmartContract> = {
sourcify_repo_url: 'https://repo.sourcify.dev/contracts//full_match/99/0x51891596E158b2857e5356DC847e2D15dFbCF2d0/',
};
export const verifiedViaEthBytecodeDb: Partial<SmartContract> = {
export const verifiedViaEthBytecodeDb: SmartContract = {
...verified,
is_verified_via_eth_bytecode_db: true,
};
export const withTwinAddress: Partial<SmartContract> = {
export const withTwinAddress: SmartContract = {
...verified,
is_verified: false,
verified_twin_address_hash: '0xa62744bee8646e237441cdbfdedd3458861748a8',
};
export const withProxyAddress: Partial<SmartContract> = {
export const withProxyAddress: SmartContract = {
...verified,
is_verified: false,
verified_twin_address_hash: '0xa62744bee8646e237441cdbfdedd3458861748a8',
minimal_proxy_address_hash: '0xa62744bee8646e237441cdbfdedd3458861748a8',
};
export const selfDestructed: Partial<SmartContract> = {
export const selfDestructed: SmartContract = {
...verified,
is_self_destructed: true,
};
export const withChangedByteCode: Partial<SmartContract> = {
export const withChangedByteCode: SmartContract = {
...verified,
is_changed_bytecode: true,
};
export const nonVerified: Partial<SmartContract> = {
export const nonVerified: SmartContract = {
is_verified: false,
creation_bytecode: 'creation_bytecode',
deployed_bytecode: 'deployed_bytecode',
is_self_destructed: false,
abi: null,
compiler_version: null,
evm_version: null,
optimization_enabled: null,
optimization_runs: null,
name: null,
verified_at: null,
is_verified_via_eth_bytecode_db: null,
is_changed_bytecode: null,
has_methods_read: false,
has_methods_read_proxy: false,
has_methods_write: false,
has_methods_write_proxy: false,
has_custom_methods_read: false,
has_custom_methods_write: false,
is_verified_via_sourcify: null,
is_fully_verified: null,
is_partially_verified: null,
sourcify_repo_url: null,
source_code: null,
constructor_args: null,
decoded_constructor_args: null,
can_be_visualized_via_sol2uml: null,
file_path: '',
additional_sources: [],
external_libraries: null,
verified_twin_address_hash: null,
minimal_proxy_address_hash: null,
language: null,
license_type: null,
};
......@@ -31,4 +31,7 @@ export const ENVS_MAP: Record<string, Array<[string, string]>> = {
userOps: [
[ 'NEXT_PUBLIC_HAS_USER_OPS', 'true' ],
],
hasContractAuditReports: [
[ 'NEXT_PUBLIC_HAS_CONTRACT_AUDIT_REPORTS', 'true' ],
],
};
......@@ -47,12 +47,6 @@ export const viewsEnvs = {
},
};
export const UIEnvs = {
hasContractAuditReports: [
{ name: 'NEXT_PUBLIC_HAS_CONTRACT_AUDIT_REPORTS', value: 'true' },
],
};
export const stabilityEnvs = [
{ name: 'NEXT_PUBLIC_VIEWS_ADDRESS_HIDDEN_VIEWS', value: '["top_accounts"]' },
{ name: 'NEXT_PUBLIC_VIEWS_TX_HIDDEN_FIELDS', value: '["value","fee_currency","gas_price","gas_fees","burnt_fees"]' },
......
......@@ -19,22 +19,16 @@ export const ADDRESS_INFO: Address = {
creation_tx_hash: null,
creator_address_hash: ADDRESS_HASH,
exchange_rate: null,
has_custom_methods_read: false,
has_custom_methods_write: false,
has_decompiled_code: false,
has_logs: true,
has_methods_read: false,
has_methods_read_proxy: false,
has_methods_write: false,
has_methods_write_proxy: false,
has_token_transfers: false,
has_tokens: false,
has_validated_blocks: false,
hash: ADDRESS_HASH,
implementation_address: null,
implementation_name: null,
is_contract: false,
is_verified: false,
is_contract: true,
is_verified: true,
name: 'ChainLink Token (goerli)',
token: TOKEN_INFO_ERC_20,
private_tags: [],
......
......@@ -7,6 +7,12 @@ export const CONTRACT_CODE_UNVERIFIED = {
creation_bytecode: '0x60806040526e',
deployed_bytecode: '0x608060405233',
is_self_destructed: false,
has_methods_read: true,
has_methods_read_proxy: true,
has_methods_write: true,
has_methods_write_proxy: true,
has_custom_methods_read: true,
has_custom_methods_write: true,
} as SmartContract;
export const CONTRACT_CODE_VERIFIED = {
......@@ -41,6 +47,12 @@ export const CONTRACT_CODE_VERIFIED = {
source_code: 'source_code',
verified_at: '2023-02-21T14:39:16.906760Z',
license_type: 'mit',
has_methods_read: true,
has_methods_read_proxy: true,
has_methods_write: true,
has_methods_write_proxy: true,
has_custom_methods_read: true,
has_custom_methods_write: true,
} as unknown as SmartContract;
export const VERIFIED_CONTRACT_INFO: VerifiedContract = {
......
......@@ -15,14 +15,8 @@ export interface Address extends UserTags {
ens_domain_name: string | null;
// TODO: if we are happy with tabs-counters method, should we delete has_something fields?
has_beacon_chain_withdrawals?: boolean;
has_custom_methods_read: boolean;
has_custom_methods_write: boolean;
has_decompiled_code: boolean;
has_logs: boolean;
has_methods_read: boolean;
has_methods_read_proxy: boolean;
has_methods_write: boolean;
has_methods_write_proxy: boolean;
has_token_transfers: boolean;
has_tokens: boolean;
has_validated_blocks: boolean;
......
......@@ -33,6 +33,14 @@ export interface SmartContract {
is_verified: boolean | null;
is_verified_via_eth_bytecode_db: boolean | null;
is_changed_bytecode: boolean | null;
has_methods_read: boolean;
has_methods_read_proxy: boolean;
has_methods_write: boolean;
has_methods_write_proxy: boolean;
has_custom_methods_read: boolean;
has_custom_methods_write: boolean;
// sourcify info >>>
is_verified_via_sourcify: boolean | null;
is_fully_verified: boolean | null;
......
......@@ -7,24 +7,29 @@ import Web3ModalProvider from 'ui/shared/Web3ModalProvider';
interface Props {
tabs: Array<RoutedSubTab>;
addressHash?: string;
isLoading: boolean;
shouldRender?: boolean;
}
const TAB_LIST_PROPS = {
columnGap: 3,
};
const AddressContract = ({ tabs }: Props) => {
const AddressContract = ({ tabs, isLoading, shouldRender }: Props) => {
const fallback = React.useCallback(() => {
const noProviderTabs = tabs.filter(({ id }) => id === 'contact_code' || id.startsWith('read_'));
const noProviderTabs = tabs.filter(({ id }) => id === 'contract_code' || id.startsWith('read_'));
return (
<RoutedTabs tabs={ noProviderTabs } variant="outline" colorScheme="gray" size="sm" tabListProps={ TAB_LIST_PROPS }/>
<RoutedTabs tabs={ noProviderTabs } variant="outline" colorScheme="gray" size="sm" tabListProps={ TAB_LIST_PROPS } isLoading={ isLoading }/>
);
}, [ tabs ]);
}, [ isLoading, tabs ]);
if (!shouldRender) {
return null;
}
return (
<Web3ModalProvider fallback={ fallback }>
<RoutedTabs tabs={ tabs } variant="outline" colorScheme="gray" size="sm" tabListProps={ TAB_LIST_PROPS }/>
<RoutedTabs tabs={ tabs } variant="outline" colorScheme="gray" size="sm" tabListProps={ TAB_LIST_PROPS } isLoading={ isLoading }/>
</Web3ModalProvider>
);
};
......
This diff is collapsed.
import { Flex, Skeleton, Button, Grid, GridItem, Alert, Link, chakra, Box, useColorModeValue } from '@chakra-ui/react';
import type { UseQueryResult } from '@tanstack/react-query';
import { useQueryClient } from '@tanstack/react-query';
import type { Channel } from 'phoenix';
import React from 'react';
import type { SocketMessage } from 'lib/socket/types';
import type { Address as AddressInfo } from 'types/api/address';
import type { SmartContract } from 'types/api/contract';
import { route } from 'nextjs-routes';
import config from 'configs/app';
import useApiQuery, { getResourceKey } from 'lib/api/useApiQuery';
import type { ResourceError } from 'lib/api/resources';
import { getResourceKey } from 'lib/api/useApiQuery';
import { CONTRACT_LICENSES } from 'lib/contracts/licenses';
import dayjs from 'lib/date/dayjs';
import useSocketChannel from 'lib/socket/useSocketChannel';
import useSocketMessage from 'lib/socket/useSocketMessage';
import * as stubs from 'stubs/contract';
import DataFetchAlert from 'ui/shared/DataFetchAlert';
import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import Hint from 'ui/shared/Hint';
......@@ -26,8 +28,8 @@ import ContractSourceCode from './ContractSourceCode';
type Props = {
addressHash?: string;
// prop for pw tests only
noSocket?: boolean;
contractQuery: UseQueryResult<SmartContract, ResourceError<unknown>>;
channel: Channel | undefined;
}
type InfoItemProps = {
......@@ -57,21 +59,13 @@ const InfoItem = chakra(({ label, content, hint, className, isLoading }: InfoIte
</GridItem>
));
const ContractCode = ({ addressHash, noSocket }: Props) => {
const [ isQueryEnabled, setIsQueryEnabled ] = React.useState(false);
const ContractCode = ({ addressHash, contractQuery, channel }: Props) => {
const [ isChangedBytecodeSocket, setIsChangedBytecodeSocket ] = React.useState<boolean>();
const queryClient = useQueryClient();
const addressInfo = queryClient.getQueryData<AddressInfo>(getResourceKey('address', { pathParams: { hash: addressHash } }));
const { data, isPlaceholderData, isError } = useApiQuery('contract', {
pathParams: { hash: addressHash },
queryOptions: {
enabled: Boolean(addressHash) && (noSocket || isQueryEnabled),
refetchOnMount: false,
placeholderData: addressInfo?.is_verified ? stubs.CONTRACT_CODE_VERIFIED : stubs.CONTRACT_CODE_UNVERIFIED,
},
});
const { data, isPlaceholderData, isError } = contractQuery;
const handleChangedBytecodeMessage: SocketMessage.AddressChangedBytecode['handler'] = React.useCallback(() => {
setIsChangedBytecodeSocket(true);
......@@ -86,14 +80,6 @@ const ContractCode = ({ addressHash, noSocket }: Props) => {
});
}, [ addressHash, queryClient ]);
const enableQuery = React.useCallback(() => setIsQueryEnabled(true), []);
const channel = useSocketChannel({
topic: `addresses:${ addressHash?.toLowerCase() }`,
isDisabled: !addressHash,
onJoin: enableQuery,
onSocketError: enableQuery,
});
useSocketMessage({
channel,
event: 'changed_bytecode',
......
......@@ -19,7 +19,11 @@ import ContractReadResult from './ContractReadResult';
import ContractMethodForm from './methodForm/ContractMethodForm';
import useWatchAccount from './useWatchAccount';
const ContractRead = () => {
interface Props {
isLoading?: boolean;
}
const ContractRead = ({ isLoading }: Props) => {
const apiFetch = useApiFetch();
const account = useWatchAccount();
const router = useRouter();
......@@ -36,7 +40,7 @@ const ContractRead = () => {
from: account?.address,
},
queryOptions: {
enabled: Boolean(addressHash),
enabled: !isLoading,
},
});
......
......@@ -19,7 +19,11 @@ import ContractMethodForm from './methodForm/ContractMethodForm';
import useContractAbi from './useContractAbi';
import { getNativeCoinValue, prepareAbi } from './utils';
const ContractWrite = () => {
interface Props {
isLoading?: boolean;
}
const ContractWrite = ({ isLoading }: Props) => {
const { data: walletClient } = useWalletClient();
const { isConnected, chainId } = useAccount();
const { switchChainAsync } = useSwitchChain();
......@@ -37,7 +41,7 @@ const ContractWrite = () => {
is_custom_abi: isCustomAbi ? 'true' : 'false',
},
queryOptions: {
enabled: Boolean(addressHash),
enabled: !isLoading,
refetchOnMount: false,
},
});
......
import { useRouter } from 'next/router';
import useApiQuery from 'lib/api/useApiQuery';
import useContractTabs from 'lib/hooks/useContractTabs';
import getQueryParamString from 'lib/router/getQueryParamString';
const ContractCode = () => {
const router = useRouter();
const hash = getQueryParamString(router.query.hash);
const addressQuery = useApiQuery('address', { pathParams: { hash } });
const { tabs } = useContractTabs(addressQuery.data, false);
const content = tabs.find(({ id }) => id === 'contract_code')?.component;
return content ?? null;
};
export default ContractCode;
......@@ -39,7 +39,7 @@ export default function useContractAbi({ addressHash, isProxy, isCustomAbi }: Pa
pathParams: { hash: addressHash },
queryParams: { is_custom_abi: 'true' },
queryOptions: {
enabled: Boolean(addressInfo?.has_custom_methods_write),
enabled: Boolean(contractInfo?.has_custom_methods_write),
refetchOnMount: false,
},
});
......
......@@ -74,14 +74,8 @@ export default function useAddressQuery({ hash }: Params): AddressQuery {
creation_tx_hash: null,
exchange_rate: null,
ens_domain_name: null,
has_custom_methods_read: false,
has_custom_methods_write: false,
has_decompiled_code: false,
has_logs: false,
has_methods_read: false,
has_methods_read_proxy: false,
has_methods_write: false,
has_methods_write_proxy: false,
has_token_transfers: false,
has_tokens: false,
has_validated_blocks: false,
......
......@@ -87,7 +87,7 @@ const AddressPageContent = () => {
const isSafeAddress = useIsSafeAddress(!addressQuery.isPlaceholderData && addressQuery.data?.is_contract ? hash : undefined);
const safeIconColor = useColorModeValue('black', 'white');
const contractTabs = useContractTabs(addressQuery.data);
const contractTabs = useContractTabs(addressQuery.data, addressQuery.isPlaceholderData);
const isLoading = addressQuery.isPlaceholderData || (config.features.userOps.isEnabled && userOpsAccountQuery.isPlaceholderData);
const isTabsLoading = isLoading || addressTabsCountersQuery.isPlaceholderData;
......@@ -178,8 +178,8 @@ const AddressPageContent = () => {
return 'Contract';
},
component: <AddressContract tabs={ contractTabs }/>,
subTabs: contractTabs.map(tab => tab.id),
component: <AddressContract tabs={ contractTabs.tabs } shouldRender={ !isTabsLoading } isLoading={ contractTabs.isLoading }/>,
subTabs: contractTabs.tabs.map(tab => tab.id),
} : undefined,
].filter(Boolean);
}, [ addressQuery.data, contractTabs, addressTabsCountersQuery.data, userOpsAccountQuery.data, isTabsLoading ]);
......
......@@ -69,7 +69,7 @@ const TokenPageContent = () => {
},
});
const contractQuery = useApiQuery('address', {
const addressQuery = useApiQuery('address', {
pathParams: { hash: hashString },
queryOptions: {
enabled: isQueryEnabled && Boolean(router.query.hash),
......@@ -119,7 +119,7 @@ const TokenPageContent = () => {
}
}, [ tokenQuery.data, tokenQuery.isPlaceholderData ]);
const hasData = (tokenQuery.data && !tokenQuery.isPlaceholderData) && (contractQuery.data && !contractQuery.isPlaceholderData);
const hasData = (tokenQuery.data && !tokenQuery.isPlaceholderData) && (addressQuery.data && !addressQuery.isPlaceholderData);
const hasInventoryTab = tokenQuery.data?.type && NFT_TOKEN_TYPE_IDS.includes(tokenQuery.data.type);
const transfersQuery = useQueryWithPages({
......@@ -172,7 +172,7 @@ const TokenPageContent = () => {
queryOptions: { enabled: Boolean(tokenQuery.data) && config.features.verifiedTokens.isEnabled },
});
const contractTabs = useContractTabs(contractQuery.data);
const contractTabs = useContractTabs(addressQuery.data, addressQuery.isPlaceholderData);
const tabs: Array<RoutedTab> = [
hasInventoryTab ? {
......@@ -182,10 +182,10 @@ const TokenPageContent = () => {
} : undefined,
{ id: 'token_transfers', title: 'Token transfers', component: <TokenTransfer transfersQuery={ transfersQuery } token={ tokenQuery.data }/> },
{ id: 'holders', title: 'Holders', component: <TokenHolders token={ tokenQuery.data } holdersQuery={ holdersQuery }/> },
contractQuery.data?.is_contract ? {
addressQuery.data?.is_contract ? {
id: 'contract',
title: () => {
if (contractQuery.data?.is_verified) {
if (addressQuery.data?.is_verified) {
return (
<>
<span>Contract</span>
......@@ -196,8 +196,8 @@ const TokenPageContent = () => {
return 'Contract';
},
component: <AddressContract tabs={ contractTabs }/>,
subTabs: contractTabs.map(tab => tab.id),
component: <AddressContract tabs={ contractTabs.tabs } isLoading={ contractTabs.isLoading }/>,
subTabs: contractTabs.tabs.map(tab => tab.id),
} : undefined,
].filter(Boolean);
......@@ -255,8 +255,8 @@ const TokenPageContent = () => {
</Tooltip>
) }
<EntityTags
data={ contractQuery.data }
isLoading={ tokenQuery.isPlaceholderData || contractQuery.isPlaceholderData }
data={ addressQuery.data }
isLoading={ tokenQuery.isPlaceholderData || addressQuery.isPlaceholderData }
tagsBefore={ [
tokenQuery.data ? { label: tokenQuery.data?.type, display_name: tokenQuery.data?.type } : undefined,
config.features.bridgedTokens.isEnabled && tokenQuery.data?.is_bridged ?
......@@ -273,19 +273,19 @@ const TokenPageContent = () => {
</>
);
const isLoading = tokenQuery.isPlaceholderData || contractQuery.isPlaceholderData;
const isLoading = tokenQuery.isPlaceholderData || addressQuery.isPlaceholderData;
const titleSecondRow = (
<Flex alignItems="center" w="100%" minW={ 0 } columnGap={ 2 } rowGap={ 2 } flexWrap={{ base: 'wrap', lg: 'nowrap' }}>
<AddressEntity
address={{ ...contractQuery.data, name: '' }}
address={{ ...addressQuery.data, name: '' }}
isLoading={ isLoading }
fontFamily="heading"
fontSize="lg"
fontWeight={ 500 }
/>
{ !isLoading && tokenQuery.data && <AddressAddToWallet token={ tokenQuery.data } variant="button"/> }
<AddressQrCode address={ contractQuery.data } isLoading={ isLoading }/>
<AddressQrCode address={ addressQuery.data } isLoading={ isLoading }/>
<AccountActionsMenu isLoading={ isLoading }/>
<Flex ml={{ base: 0, lg: 'auto' }} columnGap={ 2 } flexGrow={{ base: 1, lg: 0 }}>
<TokenVerifiedInfo verifiedInfoQuery={ verifiedInfoQuery }/>
......
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