Files
explore/ui/addressVerification/AddressVerificationModal.tsx
tom goriunovandGitHub 401dc58402 Smart wallet auth (#3220)
* basic login button implementation

* refactoring and add dynamic auth button to the other pages

* connect wallet without authenticating an user

* login and logout user in blockscout account

* refactoring and RPC overrides

* authenticate user with connected wallet

* add ENS to profile button

* override evm chains and fix contract write with waas wallet

* disconnect wallet and fix docker build

* add dynamic imports to components that use web3 wallet packages

* refactor user profile directory

* clean up

* tweaks

* update pw ci script

* fix "connect wallet" button behavior

* handle linking email to profile with dynamic provider

* fix test

* async loading web3 hooks and remove dynamic loading from components that use them

* fix pw tests

* add account navigation in horizontal layout when auth provider is dynamic

* fix address verification modal

* review fixes

* spelling fixes
2026-02-18 19:42:44 +01:00

135 lines
4.6 KiB
TypeScript

import dynamic from 'next/dynamic';
import React from 'react';
import type { AddressVerificationFormFirstStepFields, AddressCheckStatusSuccess } from './types';
import type { VerifiedAddress } from 'types/api/account';
import config from 'configs/app';
import { FallbackProvider } from 'lib/contexts/fallback';
import * as mixpanel from 'lib/mixpanel/index';
import { DialogBody, DialogContent, DialogHeader, DialogRoot } from 'toolkit/chakra/dialog';
const Web3ProviderBase = dynamic(() => import('ui/shared/web3/Web3Provider'), { ssr: false });
import AddressVerificationStepAddress from './steps/AddressVerificationStepAddress';
import AddressVerificationStepSignature from './steps/AddressVerificationStepSignature';
import AddressVerificationStepSuccess from './steps/AddressVerificationStepSuccess';
type StateData = AddressVerificationFormFirstStepFields & AddressCheckStatusSuccess & { isToken?: boolean };
const feature = config.features.blockchainInteraction;
// Dynamic providers cannot be nested, so a dummy provider is used here
const Web3Provider = feature.isEnabled && feature.connectorType === 'dynamic' ? FallbackProvider : Web3ProviderBase;
interface Props {
open: boolean;
onOpenChange: ({ open }: { open: boolean }) => void;
onSubmit: (address: VerifiedAddress) => void;
onAddTokenInfoClick: (address: string) => void;
onShowListClick: () => void;
defaultAddress?: string;
pageType: string;
}
const AddressVerificationModal = ({ defaultAddress, open, onOpenChange, onSubmit, onAddTokenInfoClick, onShowListClick, pageType }: Props) => {
const [ stepIndex, setStepIndex ] = React.useState(0);
const [ data, setData ] = React.useState<StateData>({ address: '', signingMessage: '' });
React.useEffect(() => {
open && mixpanel.logEvent(
mixpanel.EventTypes.VERIFY_ADDRESS,
{ Action: 'Form opened', 'Page type': pageType },
);
}, [ open, pageType ]);
const handleGoToSecondStep = React.useCallback((firstStepResult: typeof data) => {
setData(firstStepResult);
setStepIndex((prev) => prev + 1);
mixpanel.logEvent(
mixpanel.EventTypes.VERIFY_ADDRESS,
{ Action: 'Address entered', 'Page type': pageType },
);
}, [ pageType ]);
const handleGoToThirdStep = React.useCallback((address: VerifiedAddress, signMethod: 'wallet' | 'manual') => {
onSubmit(address);
setStepIndex((prev) => prev + 1);
setData((prev) => ({ ...prev, isToken: Boolean(address.metadata.tokenName) }));
mixpanel.logEvent(
mixpanel.EventTypes.VERIFY_ADDRESS,
{ Action: 'Sign ownership', 'Page type': pageType, 'Sign method': signMethod },
);
}, [ onSubmit, pageType ]);
const handleGoToPrevStep = React.useCallback(() => {
setStepIndex((prev) => prev - 1);
}, []);
const handleOpenChange = React.useCallback(({ open }: { open: boolean }) => {
onOpenChange({ open });
if (!open) {
setStepIndex(0);
setData({ address: '', signingMessage: '' });
}
}, [ onOpenChange ]);
const handleAddTokenInfoClick = React.useCallback(() => {
onAddTokenInfoClick(data.address);
handleOpenChange({ open: false });
}, [ handleOpenChange, data.address, onAddTokenInfoClick ]);
const steps = [
{
title: 'Verify new address ownership',
content: <AddressVerificationStepAddress onContinue={ handleGoToSecondStep } defaultAddress={ defaultAddress }/>,
},
{
title: 'Copy and sign message',
content: (
<AddressVerificationStepSignature
{ ...data }
onContinue={ handleGoToThirdStep }
noWeb3Provider={ !config.features.blockchainInteraction.isEnabled }
/>
),
},
{
title: 'Congrats! Address is verified.',
content: (
<AddressVerificationStepSuccess
onShowListClick={ onShowListClick }
onAddTokenInfoClick={ handleAddTokenInfoClick }
isToken={ data.isToken }
address={ data.address }
/>
),
},
];
const step = steps[stepIndex];
return (
<DialogRoot
open={ open }
onOpenChange={ handleOpenChange }
size={{ lgDown: 'full', lg: 'md' }}
closeOnInteractOutside={ false }
modal={ false }
trapFocus={ false }
preventScroll={ false }
>
<DialogContent>
<DialogHeader onBackToClick={ stepIndex !== 0 ? handleGoToPrevStep : undefined }>
{ step.title }
</DialogHeader>
<DialogBody mb={ 0 }>
<Web3Provider>
{ step.content }
</Web3Provider>
</DialogBody>
</DialogContent>
</DialogRoot>
);
};
export default React.memo(AddressVerificationModal);