Commit 324f675c authored by tom's avatar tom

better errors

parent ce6b8be1
...@@ -10,3 +10,6 @@ export const MINUTE = 60 * SECOND; ...@@ -10,3 +10,6 @@ export const MINUTE = 60 * SECOND;
export const HOUR = 60 * MINUTE; export const HOUR = 60 * MINUTE;
export const DAY = 24 * HOUR; export const DAY = 24 * HOUR;
export const WEEK = 7 * DAY; export const WEEK = 7 * DAY;
export const Kb = 1_000;
export const Mb = 1_000 * Kb;
...@@ -35,10 +35,13 @@ function MyApp({ Component, pageProps }: AppProps) { ...@@ -35,10 +35,13 @@ function MyApp({ Component, pageProps }: AppProps) {
}, },
})); }));
const renderErrorScreen = React.useCallback(() => { const renderErrorScreen = React.useCallback((error?: Error) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const statusCode = (error?.cause as any)?.status || 500;
return ( return (
<AppError <AppError
statusCode={ 500 } statusCode={ statusCode }
height="100vh" height="100vh"
display="flex" display="flex"
flexDirection="column" flexDirection="column"
......
...@@ -129,7 +129,7 @@ const ContractCode = () => { ...@@ -129,7 +129,7 @@ const ContractCode = () => {
<AddressLink type="address" hash={ data.verified_twin_address_hash } truncation="constant" ml={ 2 }/> <AddressLink type="address" hash={ data.verified_twin_address_hash } truncation="constant" ml={ 2 }/>
</Address> </Address>
<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>
<LinkInternal href={ link('address_contract_verification', { id: data.verified_twin_address_hash }) }>Verify & Publish</LinkInternal> <LinkInternal href={ link('address_contract_verification', { id: addressHash }) }>Verify & Publish</LinkInternal>
<span> page</span> <span> page</span>
</Alert> </Alert>
) } ) }
......
...@@ -76,9 +76,6 @@ const ContractVerificationForm = ({ method: methodFromQuery, config, hash }: Pro ...@@ -76,9 +76,6 @@ const ContractVerificationForm = ({ method: methodFromQuery, config, hash }: Pro
}, [ apiFetch, hash ]); }, [ apiFetch, hash ]);
const handleNewSocketMessage: SocketMessage.ContractVerification['handler'] = React.useCallback((payload) => { const handleNewSocketMessage: SocketMessage.ContractVerification['handler'] = React.useCallback((payload) => {
// eslint-disable-next-line no-console
console.log('__>__ handleNewSocketMessage', payload);
if (payload.status === 'error') { if (payload.status === 'error') {
const errors = formatSocketErrors(payload.errors); const errors = formatSocketErrors(payload.errors);
errors.forEach(([ field, error ]) => setError(field, error)); errors.forEach(([ field, error ]) => setError(field, error));
...@@ -100,6 +97,10 @@ const ContractVerificationForm = ({ method: methodFromQuery, config, hash }: Pro ...@@ -100,6 +97,10 @@ const ContractVerificationForm = ({ method: methodFromQuery, config, hash }: Pro
}, [ hash, router, setError, toast ]); }, [ hash, router, setError, toast ]);
const handleSocketError = React.useCallback(() => { const handleSocketError = React.useCallback(() => {
if (!formState.isSubmitting) {
return;
}
submitPromiseResolver.current?.(null); submitPromiseResolver.current?.(null);
const toastId = 'socket-error'; const toastId = 'socket-error';
...@@ -112,13 +113,13 @@ const ContractVerificationForm = ({ method: methodFromQuery, config, hash }: Pro ...@@ -112,13 +113,13 @@ const ContractVerificationForm = ({ method: methodFromQuery, config, hash }: Pro
variant: 'subtle', variant: 'subtle',
isClosable: true, isClosable: true,
}); });
}, [ toast ]); }, [ formState.isSubmitting, toast ]);
const channel = useSocketChannel({ const channel = useSocketChannel({
topic: `addresses:${ hash.toLowerCase() }`, topic: `addresses:${ hash.toLowerCase() }`,
onSocketClose: handleSocketError, onSocketClose: handleSocketError,
onSocketError: handleSocketError, onSocketError: handleSocketError,
isDisabled: !formState.isSubmitting, isDisabled: false,
}); });
useSocketMessage({ useSocketMessage({
channel, channel,
......
...@@ -5,6 +5,7 @@ import { Controller, useFormContext } from 'react-hook-form'; ...@@ -5,6 +5,7 @@ import { Controller, useFormContext } from 'react-hook-form';
import type { FormFields } from '../types'; import type { FormFields } from '../types';
import { Mb } from 'lib/consts';
import DragAndDropArea from 'ui/shared/forms/DragAndDropArea'; import DragAndDropArea from 'ui/shared/forms/DragAndDropArea';
import FieldError from 'ui/shared/forms/FieldError'; import FieldError from 'ui/shared/forms/FieldError';
import FileInput from 'ui/shared/forms/FileInput'; import FileInput from 'ui/shared/forms/FileInput';
...@@ -45,7 +46,7 @@ const ContractVerificationFieldSources = ({ fileTypes, multiple, title, classNam ...@@ -45,7 +46,7 @@ const ContractVerificationFieldSources = ({ fileTypes, multiple, title, classNam
const errorList = fileError?.message?.split(';'); const errorList = fileError?.message?.split(';');
return ( return (
<Box display="grid" gridTemplateColumns={{ base: '1fr', lg: '1fr 1fr' }} columnGap={ 3 } rowGap={ 3 }> <Box display="grid" gridTemplateColumns={{ base: 'minmax(0, 1fr)', lg: 'minmax(0, 1fr) minmax(0, 1fr)' }} columnGap={ 3 } rowGap={ 3 }>
{ files.map((file, index) => ( { files.map((file, index) => (
<Box key={ file.name + file.lastModified + index }> <Box key={ file.name + file.lastModified + index }>
<FileSnippet <FileSnippet
...@@ -92,7 +93,8 @@ const ContractVerificationFieldSources = ({ fileTypes, multiple, title, classNam ...@@ -92,7 +93,8 @@ const ContractVerificationFieldSources = ({ fileTypes, multiple, title, classNam
const validateFileType = React.useCallback(async(value: FieldPathValue<FormFields, 'sources'>): Promise<ValidateResult> => { const validateFileType = React.useCallback(async(value: FieldPathValue<FormFields, 'sources'>): Promise<ValidateResult> => {
if (Array.isArray(value)) { if (Array.isArray(value)) {
const errors = value.map(({ name }) => fileTypes.some((ext) => name.endsWith(ext)) ? '' : 'Wrong file type'); const errorText = `Wrong file type. Allowed files types are ${ fileTypes.join(',') }.`;
const errors = value.map(({ name }) => fileTypes.some((ext) => name.endsWith(ext)) ? '' : errorText);
if (errors.some((item) => item !== '')) { if (errors.some((item) => item !== '')) {
return errors.join(';'); return errors.join(';');
} }
...@@ -102,8 +104,8 @@ const ContractVerificationFieldSources = ({ fileTypes, multiple, title, classNam ...@@ -102,8 +104,8 @@ const ContractVerificationFieldSources = ({ fileTypes, multiple, title, classNam
const validateFileSize = React.useCallback(async(value: FieldPathValue<FormFields, 'sources'>): Promise<ValidateResult> => { const validateFileSize = React.useCallback(async(value: FieldPathValue<FormFields, 'sources'>): Promise<ValidateResult> => {
if (Array.isArray(value)) { if (Array.isArray(value)) {
const FILE_SIZE_LIMIT = 260; const FILE_SIZE_LIMIT = 20 * Mb;
const errors = value.map(({ size }) => size > FILE_SIZE_LIMIT ? 'File is too big' : ''); const errors = value.map(({ size }) => size > FILE_SIZE_LIMIT ? 'File is too big. Maximum size is 20 Mb.' : '');
if (errors.some((item) => item !== '')) { if (errors.some((item) => item !== '')) {
return errors.join(';'); return errors.join(';');
} }
......
...@@ -3,7 +3,7 @@ import React from 'react'; ...@@ -3,7 +3,7 @@ import React from 'react';
import ContractVerificationMethod from '../ContractVerificationMethod'; import ContractVerificationMethod from '../ContractVerificationMethod';
import ContractVerificationFieldSources from '../fields/ContractVerificationFieldSources'; import ContractVerificationFieldSources from '../fields/ContractVerificationFieldSources';
const FILE_TYPES = [ '.json' as const ]; const FILE_TYPES = [ '.json' as const, '.sol' as const ];
const ContractVerificationSourcify = () => { const ContractVerificationSourcify = () => {
return ( return (
......
...@@ -29,6 +29,17 @@ const ContractVerification = () => { ...@@ -29,6 +29,17 @@ const ContractVerification = () => {
const hash = router.query.id?.toString(); const hash = router.query.id?.toString();
const method = router.query.id?.toString() as SmartContractVerificationMethod | undefined; const method = router.query.id?.toString() as SmartContractVerificationMethod | undefined;
const contractQuery = useApiQuery('contract', {
pathParams: { id: hash },
queryOptions: {
enabled: Boolean(hash),
},
});
if (contractQuery.isError && contractQuery.error.status === 404) {
throw Error('Not found', { cause: contractQuery.error as unknown as Error });
}
const configQuery = useApiQuery('contract_verification_config', { const configQuery = useApiQuery('contract_verification_config', {
queryOptions: { queryOptions: {
select: (data: unknown) => { select: (data: unknown) => {
...@@ -50,12 +61,20 @@ const ContractVerification = () => { ...@@ -50,12 +61,20 @@ const ContractVerification = () => {
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [ ]); }, [ ]);
const isVerifiedContract = contractQuery.data?.is_verified;
React.useEffect(() => {
if (isVerifiedContract) {
router.push(link('address_index', { id: hash }, { tab: 'contract' }), undefined, { scroll: false, shallow: true });
}
}, [ hash, isVerifiedContract, router ]);
const content = (() => { const content = (() => {
if (configQuery.isError || !hash) { if (configQuery.isError || !hash || contractQuery.isError) {
return <DataFetchAlert/>; return <DataFetchAlert/>;
} }
if (configQuery.isLoading) { if (configQuery.isLoading || contractQuery.isLoading || isVerifiedContract) {
return <ContentLoader/>; return <ContentLoader/>;
} }
......
...@@ -35,7 +35,7 @@ const Page = ({ ...@@ -35,7 +35,7 @@ const Page = ({
return <PageContent isHomePage={ isHomePage }>{ content }</PageContent>; return <PageContent isHomePage={ isHomePage }>{ content }</PageContent>;
} }
return isInvalidTxHash ? <ErrorInvalidTxHash/> : <AppError statusCode={ 500 }/>; return isInvalidTxHash ? <ErrorInvalidTxHash/> : <AppError statusCode={ statusCode }/>;
}, [ isHomePage, wrapChildren ]); }, [ isHomePage, wrapChildren ]);
const renderedChildren = wrapChildren ? ( const renderedChildren = wrapChildren ? (
......
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