Commit a055d069 authored by tom's avatar tom

web3 modal and minor fixes

parent d8d2c46a
export default function shortenString(string: string | null) {
if (!string) {
return '';
}
if (string.length <= 7) {
return string;
}
return string.slice(0, 4) + '...' + string.slice(-4);
}
import { FormControl, Input } from '@chakra-ui/react'; import { FormControl, Input, useColorModeValue } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { Control, ControllerRenderProps, FormState } from 'react-hook-form'; import type { Control, ControllerRenderProps, FormState } from 'react-hook-form';
import { Controller } from 'react-hook-form'; import { Controller } from 'react-hook-form';
...@@ -15,11 +15,13 @@ interface Props { ...@@ -15,11 +15,13 @@ interface Props {
} }
const AddressVerificationFieldAddress = ({ formState, control }: Props) => { const AddressVerificationFieldAddress = ({ formState, control }: Props) => {
const backgroundColor = useColorModeValue('white', 'gray.900');
const renderControl = React.useCallback(({ field }: {field: ControllerRenderProps<Fields, 'address'>}) => { const renderControl = React.useCallback(({ field }: {field: ControllerRenderProps<Fields, 'address'>}) => {
const error = 'address' in formState.errors ? formState.errors.address : undefined; const error = 'address' in formState.errors ? formState.errors.address : undefined;
return ( return (
<FormControl variant="floating" id={ field.name } isRequired size="md"> <FormControl variant="floating" id={ field.name } isRequired size="md" backgroundColor={ backgroundColor }>
<Input <Input
{ ...field } { ...field }
required required
...@@ -31,7 +33,7 @@ const AddressVerificationFieldAddress = ({ formState, control }: Props) => { ...@@ -31,7 +33,7 @@ const AddressVerificationFieldAddress = ({ formState, control }: Props) => {
<InputPlaceholder text="Smart contract address (0x...)" error={ error }/> <InputPlaceholder text="Smart contract address (0x...)" error={ error }/>
</FormControl> </FormControl>
); );
}, [ formState.errors, formState.isSubmitting ]); }, [ formState.errors, formState.isSubmitting, backgroundColor ]);
return ( return (
<Controller <Controller
......
import { FormControl, Textarea } from '@chakra-ui/react'; import { FormControl, Textarea, useColorModeValue } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { Control, ControllerRenderProps, FormState } from 'react-hook-form'; import type { Control, ControllerRenderProps, FormState } from 'react-hook-form';
import { Controller } from 'react-hook-form'; import { Controller } from 'react-hook-form';
...@@ -15,11 +15,13 @@ interface Props { ...@@ -15,11 +15,13 @@ interface Props {
} }
const AddressVerificationFieldMessage = ({ formState, control }: Props) => { const AddressVerificationFieldMessage = ({ formState, control }: Props) => {
const backgroundColor = useColorModeValue('white', 'gray.900');
const renderControl = React.useCallback(({ field }: {field: ControllerRenderProps<Fields, 'message'>}) => { const renderControl = React.useCallback(({ field }: {field: ControllerRenderProps<Fields, 'message'>}) => {
const error = 'message' in formState.errors ? formState.errors.message : undefined; const error = 'message' in formState.errors ? formState.errors.message : undefined;
return ( return (
<FormControl variant="floating" id={ field.name } isRequired size="md"> <FormControl variant="floating" id={ field.name } isRequired size="md" backgroundColor={ backgroundColor }>
<Textarea <Textarea
{ ...field } { ...field }
required required
...@@ -28,10 +30,10 @@ const AddressVerificationFieldMessage = ({ formState, control }: Props) => { ...@@ -28,10 +30,10 @@ const AddressVerificationFieldMessage = ({ formState, control }: Props) => {
autoComplete="off" autoComplete="off"
maxH="105px" maxH="105px"
/> />
<InputPlaceholder text="Message to sign" error={ error }/> <InputPlaceholder text="Message to sign" error={ error } isInModal/>
</FormControl> </FormControl>
); );
}, [ formState.errors ]); }, [ formState.errors, backgroundColor ]);
return ( return (
<Controller <Controller
......
import { FormControl, Input } from '@chakra-ui/react'; import { FormControl, Input, useColorModeValue } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { Control, ControllerRenderProps, FormState } from 'react-hook-form'; import type { Control, ControllerRenderProps, FormState } from 'react-hook-form';
import { Controller } from 'react-hook-form'; import { Controller } from 'react-hook-form';
...@@ -16,12 +16,13 @@ interface Props { ...@@ -16,12 +16,13 @@ interface Props {
} }
const AddressVerificationFieldSignature = ({ formState, control }: Props) => { const AddressVerificationFieldSignature = ({ formState, control }: Props) => {
const backgroundColor = useColorModeValue('white', 'gray.900');
const renderControl = React.useCallback(({ field }: {field: ControllerRenderProps<Fields, 'signature'>}) => { const renderControl = React.useCallback(({ field }: {field: ControllerRenderProps<Fields, 'signature'>}) => {
const error = 'signature' in formState.errors ? formState.errors.signature : undefined; const error = 'signature' in formState.errors ? formState.errors.signature : undefined;
return ( return (
<FormControl variant="floating" id={ field.name } isRequired size="md"> <FormControl variant="floating" id={ field.name } isRequired size="md" backgroundColor={ backgroundColor }>
<Input <Input
{ ...field } { ...field }
required required
...@@ -32,7 +33,7 @@ const AddressVerificationFieldSignature = ({ formState, control }: Props) => { ...@@ -32,7 +33,7 @@ const AddressVerificationFieldSignature = ({ formState, control }: Props) => {
<InputPlaceholder text="Signature hash" error={ error }/> <InputPlaceholder text="Signature hash" error={ error }/>
</FormControl> </FormControl>
); );
}, [ formState.errors, formState.isSubmitting ]); }, [ formState.errors, formState.isSubmitting, backgroundColor ]);
return ( return (
<Controller <Controller
......
import { Alert, Box, Button, chakra, Flex, Link, Radio, RadioGroup } from '@chakra-ui/react'; import { Alert, Box, Button, chakra, Flex, Link, Radio, RadioGroup } from '@chakra-ui/react';
import { useWeb3Modal } from '@web3modal/react';
import React from 'react'; import React from 'react';
import type { SubmitHandler } from 'react-hook-form'; import type { SubmitHandler } from 'react-hook-form';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import { useSignMessage } from 'wagmi'; import { useSignMessage, useAccount } from 'wagmi';
import type { import type {
AddressVerificationFormSecondStepFields, AddressVerificationFormSecondStepFields,
...@@ -17,6 +18,7 @@ import type { VerifiedAddress } from 'types/api/account'; ...@@ -17,6 +18,7 @@ import type { VerifiedAddress } from 'types/api/account';
import appConfig from 'configs/app/config'; import appConfig from 'configs/app/config';
import type { ResourceError } from 'lib/api/resources'; import type { ResourceError } from 'lib/api/resources';
import useApiFetch from 'lib/api/useApiFetch'; import useApiFetch from 'lib/api/useApiFetch';
import shortenString from 'lib/shortenString';
import CopyToClipboard from 'ui/shared/CopyToClipboard'; import CopyToClipboard from 'ui/shared/CopyToClipboard';
import AddressVerificationFieldMessage from '../fields/AddressVerificationFieldMessage'; import AddressVerificationFieldMessage from '../fields/AddressVerificationFieldMessage';
...@@ -31,6 +33,9 @@ interface Props extends AddressVerificationFormFirstStepFields, AddressCheckStat ...@@ -31,6 +33,9 @@ interface Props extends AddressVerificationFormFirstStepFields, AddressCheckStat
const AddressVerificationStepSignature = ({ address, signingMessage, contractCreator, contractOwner, onContinue }: Props) => { const AddressVerificationStepSignature = ({ address, signingMessage, contractCreator, contractOwner, onContinue }: Props) => {
const [ signMethod, setSignMethod ] = React.useState<'wallet' | 'manually'>('wallet'); const [ signMethod, setSignMethod ] = React.useState<'wallet' | 'manually'>('wallet');
const { open: openWeb3Modal } = useWeb3Modal();
const { isConnected } = useAccount();
const formApi = useForm<Fields>({ const formApi = useForm<Fields>({
mode: 'onBlur', mode: 'onBlur',
defaultValues: { defaultValues: {
...@@ -68,7 +73,9 @@ const AddressVerificationStepSignature = ({ address, signingMessage, contractCre ...@@ -68,7 +73,9 @@ const AddressVerificationStepSignature = ({ address, signingMessage, contractCre
return setError('root', { type: 'manual', message: 'Message validity expired' }); return setError('root', { type: 'manual', message: 'Message validity expired' });
} }
case 'INVALID_SIGNER_ERROR': { case 'INVALID_SIGNER_ERROR': {
const message = `Invalid signer ${ response.invalidSigner.signer }. Expected: ${ response.invalidSigner.validAddresses.join(', ') }.`; const signer = shortenString(response.invalidSigner.signer);
const expectedSigners = [ contractCreator, contractOwner ].filter(Boolean).map(shortenString).join(', ');
const message = `Invalid signer ${ signer }. Expected: ${ expectedSigners }.`;
return setError('root', { type: 'manual', message }); return setError('root', { type: 'manual', message });
} }
case 'UNKNOWN_STATUS': { case 'UNKNOWN_STATUS': {
...@@ -86,7 +93,7 @@ const AddressVerificationStepSignature = ({ address, signingMessage, contractCre ...@@ -86,7 +93,7 @@ const AddressVerificationStepSignature = ({ address, signingMessage, contractCre
const error = _error as ResourceError<AddressVerificationResponseError>; const error = _error as ResourceError<AddressVerificationResponseError>;
setError('root', { type: 'manual', message: error.payload?.message || 'Oops! Something went wrong' }); setError('root', { type: 'manual', message: error.payload?.message || 'Oops! Something went wrong' });
} }
}, [ address, apiFetch, onContinue, setError ]); }, [ address, apiFetch, contractCreator, contractOwner, onContinue, setError ]);
const onSubmit = handleSubmit(onFormSubmit); const onSubmit = handleSubmit(onFormSubmit);
...@@ -105,15 +112,48 @@ const AddressVerificationStepSignature = ({ address, signingMessage, contractCre ...@@ -105,15 +112,48 @@ const AddressVerificationStepSignature = ({ address, signingMessage, contractCre
clearErrors('root'); clearErrors('root');
}, [ clearErrors ]); }, [ clearErrors ]);
const handleOpenWeb3Modal = React.useCallback(() => {
openWeb3Modal();
}, [ openWeb3Modal ]);
const handleWeb3SignClick = React.useCallback(() => { const handleWeb3SignClick = React.useCallback(() => {
if (!isConnected) {
return setError('root', { type: 'manual', message: 'Please connect to your Web3 wallet first' });
}
const message = getValues('message'); const message = getValues('message');
signMessage({ message }); signMessage({ message });
}, [ getValues, signMessage ]); }, [ getValues, signMessage, isConnected, setError ]);
const handleManualSignClick = React.useCallback(() => { const handleManualSignClick = React.useCallback(() => {
onSubmit(); onSubmit();
}, [ onSubmit ]); }, [ onSubmit ]);
const button = (() => {
if (signMethod === 'manually') {
return (
<Button
size="lg"
onClick={ handleManualSignClick }
isLoading={ formState.isSubmitting }
loadingText="Verifying"
>
Verify
</Button>
);
}
return (
<Button
size="lg"
onClick={ isConnected ? handleWeb3SignClick : handleOpenWeb3Modal }
isLoading={ formState.isSubmitting || isSigning }
loadingText={ isSigning ? 'Signing' : 'Verifying' }
>
{ isConnected ? 'Sign and verify' : 'Connect wallet' }
</Button>
);
})();
return ( return (
<form noValidate onSubmit={ onSubmit }> <form noValidate onSubmit={ onSubmit }>
{ formState.errors.root?.type === 'manual' && <Alert status="warning" mb={ 6 }>{ formState.errors.root.message }</Alert> } { formState.errors.root?.type === 'manual' && <Alert status="warning" mb={ 6 }>{ formState.errors.root.message }</Alert> }
...@@ -149,14 +189,7 @@ const AddressVerificationStepSignature = ({ address, signingMessage, contractCre ...@@ -149,14 +189,7 @@ const AddressVerificationStepSignature = ({ address, signingMessage, contractCre
{ signMethod === 'manually' && <AddressVerificationFieldSignature formState={ formState } control={ control }/> } { signMethod === 'manually' && <AddressVerificationFieldSignature formState={ formState } control={ control }/> }
</Flex> </Flex>
<Flex alignItems="center" mt={ 8 } columnGap={ 5 }> <Flex alignItems="center" mt={ 8 } columnGap={ 5 }>
<Button { button }
size="lg"
onClick={ signMethod === 'manually' ? handleManualSignClick : handleWeb3SignClick }
isLoading={ formState.isSubmitting || isSigning }
loadingText={ isSigning ? 'Signing' : 'Verifying' }
>
{ signMethod === 'manually' ? 'Verify' : 'Sign and verify' }
</Button>
</Flex> </Flex>
</form> </form>
); );
......
import { Tooltip } from '@chakra-ui/react'; import { Tooltip } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import shortenString from 'lib/shortenString';
interface Props { interface Props {
hash: string; hash: string;
isTooltipDisabled?: boolean; isTooltipDisabled?: boolean;
...@@ -13,7 +15,7 @@ const HashStringShorten = ({ hash, isTooltipDisabled }: Props) => { ...@@ -13,7 +15,7 @@ const HashStringShorten = ({ hash, isTooltipDisabled }: Props) => {
return ( return (
<Tooltip label={ hash } isDisabled={ isTooltipDisabled }> <Tooltip label={ hash } isDisabled={ isTooltipDisabled }>
{ hash.slice(0, 4) + '...' + hash.slice(-4) } { shortenString(hash) }
</Tooltip> </Tooltip>
); );
}; };
......
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