import { useCallback , useState } from 'react' ; import { useAsyncRetry } from 'react-use' ; import { DialogContent } from '@mui/material' ; import { makeStyles , useStylesExtends } from '@masknet/theme' ; import { safeUnreachable } from '@dimensiondev/kit' ; import { ChainId , getChainDetailedCAIP , getChainIdFromNetworkType , NetworkType , ProviderType , resolveNetworkName , resolveProviderName , } from '@masknet/web3-shared-evm' ; import { useRemoteControlledDialog } from '@masknet/shared' ; import { delay } from '@masknet/shared-base' ; import { InjectedDialog } from '../../../../components/shared/InjectedDialog' ; import { WalletMessages , WalletRPC } from '../../messages' ; import { ConnectionProgress } from './ConnectionProgress' ; import Services from '../../../../extension/service' ; const useStyles = makeStyles ( ) ( ( theme ) => ( { content : { padding : theme . spacing ( 5 ) , } , } ) ) ; export interface ConnectWalletDialogProps { } export function ConnectWalletDialog ( props ) { const classes = useStylesExtends ( useStyles ( ) , props ) ; const [ providerType , setProviderType ] = useState < ProviderType | undefined > ( ) ; const [ networkType , setNetworkType ] = useState < NetworkType | undefined > ( ) ; const { open , setDialog : setConnectWalletDialog } = useRemoteControlledDialog ( WalletMessages . events . connectWalletDialogUpdated , ( ev ) => { if ( ! ev . open ) return ; setProviderType ( ev . providerType ) ; setNetworkType ( ev . networkType ) ; } ) ; const { setDialog : setWalletConnectDialog } = useRemoteControlledDialog ( WalletMessages . events . walletConnectQRCodeDialogUpdated ) ; const connectTo = useCallback ( async ( ) => { if ( ! networkType ) throw new Error ( 'Unknown network type.' ) ; if ( ! providerType ) throw new Error ( 'Unknown provider type.' ) ; const expectedChainId = getChainIdFromNetworkType ( networkType ) ; const chainDetailedCAIP = getChainDetailedCAIP ( expectedChainId ) ; if ( ! chainDetailedCAIP ) throw new Error ( 'Unknown network type.' ) ; await delay ( 1000 ) ; let account ; let chainId ; switch ( providerType ) { case ProviderType . MaskWallet : ; ( { account , chainId } = await Services . Ethereum . connectMaskWallet ( networkType ) ) ; break ; case ProviderType . MetaMask : ; ( { account , chainId } = await Services . Ethereum . connectMetaMask ( ) ) ; break ; case ProviderType . WalletConnect : const uri = await Services . Ethereum . createConnectionURI ( ) ; if ( ! uri ) throw new Error ( 'Failed to create connection URI.' ) ; setWalletConnectDialog ( { open : true , uri , } ) ; ( { account , chainId } = await Services . Ethereum . connectWalletConnect ( ) ) ; break ; case ProviderType . Coin98 : case ProviderType . WalletLink : case ProviderType . MathWallet : ; ( { account , chainId } = await Services . Ethereum . connectInjected ( ) ) ; break ; case ProviderType . Fortmatic : ; ( { account , chainId } = await Services . Ethereum . connectFortmatic ( expectedChainId ) ) ; break ; case ProviderType . CustomNetwork : throw new Error ( 'To be implemented.' ) ; default : safeUnreachable ( providerType ) ; break ; } if ( ! account || ! networkType ) throw new Error ( `Failed to connect to ${ resolveProviderName ( providerType ) }.` ) ; if ( chainId !== expectedChainId && providerType !== ProviderType . Coin98 ) { try { const overrides = { chainId : expectedChainId , providerType , } ; await Promise . race ( [ ( async ( ) => { await delay ( 30 * 1000 ) ; throw new Error ( 'Timeout!' ) ; } ) ( ) , networkType === NetworkType . Ethereum ? Services . Ethereum . switchEthereumChain ( ChainId . Mainnet , overrides ) : Services . Ethereum . addEthereumChain ( chainDetailedCAIP , account , overrides ) , ] ) ; const chainIdHex = await Services . Ethereum . getChainId ( overrides ) ; if ( Number . parseInt ( chainIdHex , 16 ) !== expectedChainId ) throw new Error ( 'Failed to switch chain.' ) ; } catch { throw new Error ( `Make sure your wallet is on the ${ resolveNetworkName ( networkType ) } network.` ) ; } } await WalletRPC . updateAccount ( { account , chainId : expectedChainId , networkType , providerType , } ) ; return true as const ; } , [ networkType , providerType ] ) ; const connection = useAsyncRetry < true > ( async ( ) => { if ( ! open ) return true ; await connectTo ( ) ; await delay ( 1000 ) ; setConnectWalletDialog ( { open : false , result : true , } ) ; return true ; } , [ open , connectTo , setConnectWalletDialog ] ) ; if ( ! providerType ) return null ; return ( < InjectedDialog title = { `Connect to ${ resolveProviderName ( providerType ) }` } open = { open } onClose = { ( ) => setConnectWalletDialog ( { open : false , result : false } ) } > < DialogContent className = { classes . content } > < ConnectionProgress providerType = { providerType } connection = { connection } / > < /DialogContent> < /InjectedDialog>); }