Commit 0dd6087f authored by tom goriunov's avatar tom goriunov Committed by GitHub

Remove `proxy_type` field from SmartContract model (#2671)

* remove `proxy_type` field from SmartContract model

* fix ts
parent c9894eb8
...@@ -43,7 +43,6 @@ export const verified: SmartContract = { ...@@ -43,7 +43,6 @@ export const verified: SmartContract = {
file_path: '', file_path: '',
additional_sources: [], additional_sources: [],
verified_twin_address_hash: null, verified_twin_address_hash: null,
proxy_type: null,
}; };
export const certified: SmartContract = { export const certified: SmartContract = {
...@@ -85,7 +84,6 @@ export const withProxyAddress: SmartContract = { ...@@ -85,7 +84,6 @@ export const withProxyAddress: SmartContract = {
...verified, ...verified,
is_verified: false, is_verified: false,
verified_twin_address_hash: '0xa62744bee8646e237441cdbfdedd3458861748a8', verified_twin_address_hash: '0xa62744bee8646e237441cdbfdedd3458861748a8',
proxy_type: 'eip1967',
}; };
export const selfDestructed: SmartContract = { export const selfDestructed: SmartContract = {
...@@ -146,7 +144,6 @@ export const nonVerified: SmartContract = { ...@@ -146,7 +144,6 @@ export const nonVerified: SmartContract = {
additional_sources: [], additional_sources: [],
external_libraries: null, external_libraries: null,
verified_twin_address_hash: null, verified_twin_address_hash: null,
proxy_type: null,
language: null, language: null,
license_type: null, license_type: null,
}; };
...@@ -69,7 +69,6 @@ export interface SmartContract { ...@@ -69,7 +69,6 @@ export interface SmartContract {
}; };
verified_twin_address_hash: string | null; verified_twin_address_hash: string | null;
verified_twin_filecoin_robust_address?: string | null; verified_twin_filecoin_robust_address?: string | null;
proxy_type: SmartContractProxyType | null;
language: string | null; language: string | null;
license_type: SmartContractLicenseType | null; license_type: SmartContractLicenseType | null;
certified?: boolean; certified?: boolean;
......
...@@ -6,7 +6,7 @@ import type { Channel } from 'phoenix'; ...@@ -6,7 +6,7 @@ import type { Channel } from 'phoenix';
import React from 'react'; import React from 'react';
import type { SocketMessage } from 'lib/socket/types'; import type { SocketMessage } from 'lib/socket/types';
import type { Address as AddressInfo } from 'types/api/address'; import type { Address } from 'types/api/address';
import type { AddressImplementation } from 'types/api/addressParams'; import type { AddressImplementation } from 'types/api/addressParams';
import type { SmartContract } from 'types/api/contract'; import type { SmartContract } from 'types/api/contract';
...@@ -27,30 +27,29 @@ const TAB_LIST_PROPS = { flexWrap: 'wrap', rowGap: 2 }; ...@@ -27,30 +27,29 @@ const TAB_LIST_PROPS = { flexWrap: 'wrap', rowGap: 2 };
const LEFT_SLOT_PROPS = { w: { base: '100%', lg: 'auto' } }; const LEFT_SLOT_PROPS = { w: { base: '100%', lg: 'auto' } };
type Props = { type Props = {
addressHash: string; addressData: Address;
channel: Channel | undefined; channel: Channel | undefined;
mainContractQuery: UseQueryResult<SmartContract, ResourceError>; mainContractQuery: UseQueryResult<SmartContract, ResourceError>;
}; };
const ContractDetails = ({ addressHash, channel, mainContractQuery }: Props) => { const ContractDetails = ({ addressData, channel, mainContractQuery }: Props) => {
const router = useRouter(); const router = useRouter();
const sourceAddress = getQueryParamString(router.query.source_address); const sourceAddress = getQueryParamString(router.query.source_address);
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const addressInfo = queryClient.getQueryData<AddressInfo>(getResourceKey('address', { pathParams: { hash: addressHash } }));
const sourceItems: Array<AddressImplementation> = React.useMemo(() => { const sourceItems: Array<AddressImplementation> = React.useMemo(() => {
const currentAddressDefaultName = addressInfo?.proxy_type === 'eip7702' ? 'Current address' : 'Current contract'; const currentAddressDefaultName = addressData?.proxy_type === 'eip7702' ? 'Current address' : 'Current contract';
const currentAddressItem = { address: addressHash, name: addressInfo?.name || currentAddressDefaultName }; const currentAddressItem = { address: addressData.hash, name: addressData?.name || currentAddressDefaultName };
if (!addressInfo || !addressInfo.implementations || addressInfo.implementations.length === 0) { if (!addressData || !addressData.implementations || addressData.implementations.length === 0) {
return [ currentAddressItem ]; return [ currentAddressItem ];
} }
return [ return [
currentAddressItem, currentAddressItem,
...(addressInfo?.implementations.filter((item) => item.address !== addressHash && item.name) || []), ...(addressData?.implementations.filter((item) => item.address !== addressData.hash && item.name) || []),
]; ];
}, [ addressInfo, addressHash ]); }, [ addressData ]);
const [ selectedItem, setSelectedItem ] = React.useState(sourceItems.find((item) => item.address === sourceAddress) || sourceItems[0]); const [ selectedItem, setSelectedItem ] = React.useState(sourceItems.find((item) => item.address === sourceAddress) || sourceItems[0]);
...@@ -59,21 +58,21 @@ const ContractDetails = ({ addressHash, channel, mainContractQuery }: Props) => ...@@ -59,21 +58,21 @@ const ContractDetails = ({ addressHash, channel, mainContractQuery }: Props) =>
queryOptions: { queryOptions: {
enabled: Boolean(selectedItem?.address && !mainContractQuery.isPlaceholderData), enabled: Boolean(selectedItem?.address && !mainContractQuery.isPlaceholderData),
refetchOnMount: false, refetchOnMount: false,
placeholderData: addressInfo?.is_verified ? stubs.CONTRACT_CODE_VERIFIED : stubs.CONTRACT_CODE_UNVERIFIED, placeholderData: addressData?.is_verified ? stubs.CONTRACT_CODE_VERIFIED : stubs.CONTRACT_CODE_UNVERIFIED,
}, },
}); });
const { data, isPlaceholderData, isError } = contractQuery; const { data, isPlaceholderData, isError } = contractQuery;
const tabs = useContractDetailsTabs({ data, isLoading: isPlaceholderData, addressHash, sourceAddress: selectedItem.address }); const tabs = useContractDetailsTabs({ data, isLoading: isPlaceholderData, addressData, sourceAddress: selectedItem.address });
const handleContractWasVerifiedMessage: SocketMessage.SmartContractWasVerified['handler'] = React.useCallback(() => { const handleContractWasVerifiedMessage: SocketMessage.SmartContractWasVerified['handler'] = React.useCallback(() => {
queryClient.refetchQueries({ queryClient.refetchQueries({
queryKey: getResourceKey('address', { pathParams: { hash: addressHash } }), queryKey: getResourceKey('address', { pathParams: { hash: addressData.hash } }),
}); });
queryClient.refetchQueries({ queryClient.refetchQueries({
queryKey: getResourceKey('contract', { pathParams: { hash: addressHash } }), queryKey: getResourceKey('contract', { pathParams: { hash: addressData.hash } }),
}); });
}, [ addressHash, queryClient ]); }, [ addressData.hash, queryClient ]);
useSocketMessage({ useSocketMessage({
channel, channel,
...@@ -101,14 +100,14 @@ const ContractDetails = ({ addressHash, channel, mainContractQuery }: Props) => ...@@ -101,14 +100,14 @@ const ContractDetails = ({ addressHash, channel, mainContractQuery }: Props) =>
<ContractDetailsAlerts <ContractDetailsAlerts
data={ mainContractQuery.data } data={ mainContractQuery.data }
isLoading={ mainContractQuery.isPlaceholderData } isLoading={ mainContractQuery.isPlaceholderData }
addressHash={ addressHash } addressData={ addressData }
channel={ channel } channel={ channel }
/> />
{ mainContractQuery.data?.is_verified && ( { mainContractQuery.data?.is_verified && (
<ContractDetailsInfo <ContractDetailsInfo
data={ mainContractQuery.data } data={ mainContractQuery.data }
isLoading={ mainContractQuery.isPlaceholderData } isLoading={ mainContractQuery.isPlaceholderData }
addressHash={ addressHash } addressHash={ addressData.hash }
/> />
) } ) }
{ tabs.length > 1 ? ( { tabs.length > 1 ? (
......
...@@ -5,16 +5,16 @@ import { test, expect } from 'playwright/lib'; ...@@ -5,16 +5,16 @@ import { test, expect } from 'playwright/lib';
import ContractDetailsAlertProxyPattern from './ContractDetailsAlertProxyPattern'; import ContractDetailsAlertProxyPattern from './ContractDetailsAlertProxyPattern';
test('proxy type with link +@mobile', async({ render }) => { test('proxy type with link +@mobile', async({ render }) => {
const component = await render(<ContractDetailsAlertProxyPattern type="eip1167"/>); const component = await render(<ContractDetailsAlertProxyPattern type="eip1167" isLoading={ false }/>);
await expect(component).toHaveScreenshot(); await expect(component).toHaveScreenshot();
}); });
test('proxy type with link but without description', async({ render }) => { test('proxy type with link but without description', async({ render }) => {
const component = await render(<ContractDetailsAlertProxyPattern type="master_copy"/>); const component = await render(<ContractDetailsAlertProxyPattern type="master_copy" isLoading={ false }/>);
await expect(component).toHaveScreenshot(); await expect(component).toHaveScreenshot();
}); });
test('proxy type without link', async({ render }) => { test('proxy type without link', async({ render }) => {
const component = await render(<ContractDetailsAlertProxyPattern type="basic_implementation"/>); const component = await render(<ContractDetailsAlertProxyPattern type="basic_implementation" isLoading={ false }/>);
await expect(component).toHaveScreenshot(); await expect(component).toHaveScreenshot();
}); });
...@@ -7,6 +7,7 @@ import { Link } from 'toolkit/chakra/link'; ...@@ -7,6 +7,7 @@ import { Link } from 'toolkit/chakra/link';
interface Props { interface Props {
type: NonNullable<SmartContractProxyType>; type: NonNullable<SmartContractProxyType>;
isLoading: boolean;
} }
const PROXY_TYPES: Partial<Record<NonNullable<SmartContractProxyType>, { const PROXY_TYPES: Partial<Record<NonNullable<SmartContractProxyType>, {
...@@ -62,7 +63,7 @@ const PROXY_TYPES: Partial<Record<NonNullable<SmartContractProxyType>, { ...@@ -62,7 +63,7 @@ const PROXY_TYPES: Partial<Record<NonNullable<SmartContractProxyType>, {
}, },
}; };
const ContractCodeProxyPattern = ({ type }: Props) => { const ContractCodeProxyPattern = ({ type, isLoading }: Props) => {
const proxyInfo = PROXY_TYPES[type]; const proxyInfo = PROXY_TYPES[type];
if (!proxyInfo || type === 'unknown') { if (!proxyInfo || type === 'unknown') {
...@@ -70,7 +71,7 @@ const ContractCodeProxyPattern = ({ type }: Props) => { ...@@ -70,7 +71,7 @@ const ContractCodeProxyPattern = ({ type }: Props) => {
} }
return ( return (
<Alert status="warning" whiteSpace="pre-wrap"> <Alert status="warning" whiteSpace="pre-wrap" loading={ isLoading }>
{ proxyInfo.link ? ( { proxyInfo.link ? (
<> <>
This proxy smart-contract is detected via <Link href={ proxyInfo.link } external>{ proxyInfo.name }</Link> This proxy smart-contract is detected via <Link href={ proxyInfo.link } external>{ proxyInfo.name }</Link>
......
...@@ -15,7 +15,7 @@ test('verified with changed byte code socket', async({ render, createSocket }) = ...@@ -15,7 +15,7 @@ test('verified with changed byte code socket', async({ render, createSocket }) =
const props = { const props = {
data: contractMock.verified, data: contractMock.verified,
isLoading: false, isLoading: false,
addressHash: addressMock.contract.hash, addressData: addressMock.contract,
}; };
const component = await render(<ContractDetailsAlerts { ...props }/>, undefined, { withSocket: true }); const component = await render(<ContractDetailsAlerts { ...props }/>, undefined, { withSocket: true });
const socket = await createSocket(); const socket = await createSocket();
...@@ -29,7 +29,7 @@ test('verified via sourcify', async({ render }) => { ...@@ -29,7 +29,7 @@ test('verified via sourcify', async({ render }) => {
const props = { const props = {
data: contractMock.verifiedViaSourcify, data: contractMock.verifiedViaSourcify,
isLoading: false, isLoading: false,
addressHash: addressMock.contract.hash, addressData: addressMock.contract,
}; };
const component = await render(<ContractDetailsAlerts { ...props }/>, undefined, { withSocket: true }); const component = await render(<ContractDetailsAlerts { ...props }/>, undefined, { withSocket: true });
...@@ -40,7 +40,7 @@ test('verified via eth bytecode db', async({ render }) => { ...@@ -40,7 +40,7 @@ test('verified via eth bytecode db', async({ render }) => {
const props = { const props = {
data: contractMock.verifiedViaEthBytecodeDb, data: contractMock.verifiedViaEthBytecodeDb,
isLoading: false, isLoading: false,
addressHash: addressMock.contract.hash, addressData: addressMock.contract,
}; };
const component = await render(<ContractDetailsAlerts { ...props }/>, undefined, { withSocket: true }); const component = await render(<ContractDetailsAlerts { ...props }/>, undefined, { withSocket: true });
...@@ -51,7 +51,7 @@ test('with twin address alert +@mobile', async({ render }) => { ...@@ -51,7 +51,7 @@ test('with twin address alert +@mobile', async({ render }) => {
const props = { const props = {
data: contractMock.withTwinAddress, data: contractMock.withTwinAddress,
isLoading: false, isLoading: false,
addressHash: addressMock.contract.hash, addressData: addressMock.contract,
}; };
const component = await render(<ContractDetailsAlerts { ...props }/>, undefined, { withSocket: true }); const component = await render(<ContractDetailsAlerts { ...props }/>, undefined, { withSocket: true });
......
...@@ -7,7 +7,7 @@ import ContractDetailsAlerts from './ContractDetailsAlerts'; ...@@ -7,7 +7,7 @@ import ContractDetailsAlerts from './ContractDetailsAlerts';
const ContractDetailsAlertsPwStory = (props: Props) => { const ContractDetailsAlertsPwStory = (props: Props) => {
const channel = useSocketChannel({ const channel = useSocketChannel({
topic: `addresses:${ props.addressHash.toLowerCase() }`, topic: `addresses:${ props.addressData.hash.toLowerCase() }`,
isDisabled: false, isDisabled: false,
}); });
......
...@@ -3,6 +3,7 @@ import type { Channel } from 'phoenix'; ...@@ -3,6 +3,7 @@ import type { Channel } from 'phoenix';
import React from 'react'; import React from 'react';
import type { SocketMessage } from 'lib/socket/types'; import type { SocketMessage } from 'lib/socket/types';
import type { Address } from 'types/api/address';
import type { SmartContract } from 'types/api/contract'; import type { SmartContract } from 'types/api/contract';
import { route } from 'nextjs-routes'; import { route } from 'nextjs-routes';
...@@ -10,7 +11,6 @@ import { route } from 'nextjs-routes'; ...@@ -10,7 +11,6 @@ import { route } from 'nextjs-routes';
import useSocketMessage from 'lib/socket/useSocketMessage'; import useSocketMessage from 'lib/socket/useSocketMessage';
import { Alert } from 'toolkit/chakra/alert'; import { Alert } from 'toolkit/chakra/alert';
import { Link } from 'toolkit/chakra/link'; import { Link } from 'toolkit/chakra/link';
import { Skeleton } from 'toolkit/chakra/skeleton';
import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import ContractDetailsVerificationButton from '../ContractDetailsVerificationButton'; import ContractDetailsVerificationButton from '../ContractDetailsVerificationButton';
...@@ -20,11 +20,11 @@ import ContractDetailsAlertVerificationSource from './ContractDetailsAlertVerifi ...@@ -20,11 +20,11 @@ import ContractDetailsAlertVerificationSource from './ContractDetailsAlertVerifi
export interface Props { export interface Props {
data: SmartContract | undefined; data: SmartContract | undefined;
isLoading: boolean; isLoading: boolean;
addressHash: string; addressData: Address;
channel?: Channel; channel?: Channel;
} }
const ContractDetailsAlerts = ({ data, isLoading, addressHash, channel }: Props) => { const ContractDetailsAlerts = ({ data, isLoading, addressData, channel }: Props) => {
const [ isChangedBytecodeSocket, setIsChangedBytecodeSocket ] = React.useState<boolean>(); const [ isChangedBytecodeSocket, setIsChangedBytecodeSocket ] = React.useState<boolean>();
const handleChangedBytecodeMessage: SocketMessage.AddressChangedBytecode['handler'] = React.useCallback(() => { const handleChangedBytecodeMessage: SocketMessage.AddressChangedBytecode['handler'] = React.useCallback(() => {
...@@ -48,20 +48,18 @@ const ContractDetailsAlerts = ({ data, isLoading, addressHash, channel }: Props) ...@@ -48,20 +48,18 @@ const ContractDetailsAlerts = ({ data, isLoading, addressHash, channel }: Props)
</Box> </Box>
) } ) }
{ data?.is_verified && ( { data?.is_verified && (
<Skeleton loading={ isLoading }> <Alert status="success" loading={ isLoading } descriptionProps={{ alignItems: 'center', flexWrap: 'wrap', rowGap: 3, columnGap: 5 }}>
<Alert status="success" descriptionProps={{ alignItems: 'center', flexWrap: 'wrap', rowGap: 3, columnGap: 5 }}> <span>Contract Source Code Verified ({ data.is_partially_verified ? 'Partial' : 'Exact' } Match)</span>
<span>Contract Source Code Verified ({ data.is_partially_verified ? 'Partial' : 'Exact' } Match)</span> {
{ data.is_partially_verified ? (
data.is_partially_verified ? ( <ContractDetailsVerificationButton
<ContractDetailsVerificationButton isLoading={ isLoading }
isLoading={ isLoading } addressHash={ addressData.hash }
addressHash={ addressHash } isPartiallyVerified
isPartiallyVerified />
/> ) : null
) : null }
} </Alert>
</Alert>
</Skeleton>
) } ) }
<ContractDetailsAlertVerificationSource data={ data }/> <ContractDetailsAlertVerificationSource data={ data }/>
{ (data?.is_changed_bytecode || isChangedBytecodeSocket) && ( { (data?.is_changed_bytecode || isChangedBytecodeSocket) && (
...@@ -69,7 +67,7 @@ const ContractDetailsAlerts = ({ data, isLoading, addressHash, channel }: Props) ...@@ -69,7 +67,7 @@ const ContractDetailsAlerts = ({ data, isLoading, addressHash, channel }: Props)
Warning! Contract bytecode has been changed and does not match the verified one. Therefore, interaction with this smart contract may be risky. Warning! Contract bytecode has been changed and does not match the verified one. Therefore, interaction with this smart contract may be risky.
</Alert> </Alert>
) } ) }
{ !data?.is_verified && data?.verified_twin_address_hash && (!data?.proxy_type || data.proxy_type === 'unknown') && ( { !data?.is_verified && data?.verified_twin_address_hash && (!addressData.proxy_type || addressData.proxy_type === 'unknown') && (
<Alert status="warning" whiteSpace="pre-wrap"> <Alert status="warning" whiteSpace="pre-wrap">
<span>Contract is not verified. However, we found a verified contract with the same bytecode in Blockscout DB </span> <span>Contract is not verified. However, we found a verified contract with the same bytecode in Blockscout DB </span>
<AddressEntity <AddressEntity
...@@ -79,13 +77,13 @@ const ContractDetailsAlerts = ({ data, isLoading, addressHash, channel }: Props) ...@@ -79,13 +77,13 @@ const ContractDetailsAlerts = ({ data, isLoading, addressHash, channel }: Props)
fontWeight="500" fontWeight="500"
/> />
<chakra.span mt={ 1 }>All functions displayed below are from ABI of that contract. In order to verify current contract, proceed with </chakra.span> <chakra.span mt={ 1 }>All functions displayed below are from ABI of that contract. In order to verify current contract, proceed with </chakra.span>
<Link href={ route({ pathname: '/address/[hash]/contract-verification', query: { hash: addressHash } }) }> <Link href={ route({ pathname: '/address/[hash]/contract-verification', query: { hash: addressData.hash } }) }>
Verify & Publish Verify & Publish
</Link> </Link>
<span> page</span> <span> page</span>
</Alert> </Alert>
) } ) }
{ data?.proxy_type && <ContractDetailsAlertProxyPattern type={ data.proxy_type }/> } { addressData.proxy_type && <ContractDetailsAlertProxyPattern type={ addressData.proxy_type } isLoading={ isLoading }/> }
</Flex> </Flex>
); );
}; };
......
import { Flex } from '@chakra-ui/react'; import { Flex } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { Address } from 'types/api/address';
import type { SmartContract } from 'types/api/contract'; import type { SmartContract } from 'types/api/contract';
import { Alert } from 'toolkit/chakra/alert'; import { Alert } from 'toolkit/chakra/alert';
...@@ -21,19 +22,19 @@ interface Tab { ...@@ -21,19 +22,19 @@ interface Tab {
interface Props { interface Props {
data: SmartContract | undefined; data: SmartContract | undefined;
isLoading: boolean; isLoading: boolean;
addressHash: string; addressData: Address;
sourceAddress: string; sourceAddress: string;
} }
export default function useContractDetailsTabs({ data, isLoading, addressHash, sourceAddress }: Props): Array<Tab> { export default function useContractDetailsTabs({ data, isLoading, addressData, sourceAddress }: Props): Array<Tab> {
const canBeVerified = !data?.is_self_destructed && !data?.is_verified && data?.proxy_type !== 'eip7702'; const canBeVerified = !data?.is_self_destructed && !data?.is_verified && addressData?.proxy_type !== 'eip7702';
return React.useMemo(() => { return React.useMemo(() => {
const verificationButton = ( const verificationButton = (
<ContractDetailsVerificationButton <ContractDetailsVerificationButton
isLoading={ isLoading } isLoading={ isLoading }
addressHash={ addressHash } addressHash={ addressData.hash }
isPartiallyVerified={ Boolean(data?.is_partially_verified) } isPartiallyVerified={ Boolean(data?.is_partially_verified) }
/> />
); );
...@@ -117,5 +118,5 @@ export default function useContractDetailsTabs({ data, isLoading, addressHash, s ...@@ -117,5 +118,5 @@ export default function useContractDetailsTabs({ data, isLoading, addressHash, s
), ),
} : undefined, } : undefined,
].filter(Boolean); ].filter(Boolean);
}, [ isLoading, addressHash, data, sourceAddress, canBeVerified ]); }, [ isLoading, addressData, data, sourceAddress, canBeVerified ]);
} }
...@@ -74,10 +74,10 @@ export default function useContractTabs(data: Address | undefined, isPlaceholder ...@@ -74,10 +74,10 @@ export default function useContractTabs(data: Address | undefined, isPlaceholder
return React.useMemo(() => { return React.useMemo(() => {
return { return {
tabs: [ tabs: [
data?.hash && { data && {
id: 'contract_code' as const, id: 'contract_code' as const,
title: 'Code', title: 'Code',
component: <ContractDetails mainContractQuery={ contractQuery } channel={ channel } addressHash={ data.hash }/>, component: <ContractDetails mainContractQuery={ contractQuery } channel={ channel } addressData={ data }/>,
subTabs: CONTRACT_DETAILS_TAB_IDS as unknown as Array<string>, subTabs: CONTRACT_DETAILS_TAB_IDS as unknown as Array<string>,
}, },
contractQuery.data?.abi && { contractQuery.data?.abi && {
...@@ -92,7 +92,7 @@ export default function useContractTabs(data: Address | undefined, isPlaceholder ...@@ -92,7 +92,7 @@ export default function useContractTabs(data: Address | undefined, isPlaceholder
<ContractMethodsProxy <ContractMethodsProxy
implementations={ verifiedImplementations } implementations={ verifiedImplementations }
isLoading={ contractQuery.isPlaceholderData } isLoading={ contractQuery.isPlaceholderData }
proxyType={ contractQuery.data?.proxy_type } proxyType={ data?.proxy_type }
/> />
), ),
}, },
...@@ -112,7 +112,7 @@ export default function useContractTabs(data: Address | undefined, isPlaceholder ...@@ -112,7 +112,7 @@ export default function useContractTabs(data: Address | undefined, isPlaceholder
isLoading: contractQuery.isPlaceholderData, isLoading: contractQuery.isPlaceholderData,
}; };
}, [ }, [
data?.hash, data,
contractQuery, contractQuery,
channel, channel,
verifiedImplementations, verifiedImplementations,
......
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