import { useCallback , useEffect , useMemo , useState } from 'react' ; import { Web3Provider } from '@ethersproject/providers' ; import { AbstractConnector } from '@web3-react/abstract-connector' ; import { useWeb3React } from '@web3-react/core' ; import { useAuthActions } from 'contexts/auth/AuthContext' ; import useFetcher from 'contexts/swr/useFetcher' ; import { isWeb3Error , Web3Error } from 'types/Error' ; import { INITIAL , PROMPT_SIGNATURE , PendingState , LISTENING_ONCHAIN } from 'types/Wallet' ; import Mixpanel from 'utils/mixpanel' ; import GnosisSafePendingMessage from '../GnosisSafePendingMessage' ; import { fetchNonce , loginOrCreateUser } from '../authRequestUtils' ; import { GNOSIS_SAFE_WALLET_TYPE_ID , listenForGnosisSignature , validateNonceSignedByGnosis , signMessageWithContractAccount , } from '../walletUtils' ; import { GNOSIS_NONCE_STORAGE_KEY } from 'constants/storageKeys' ; import { getLocalStorageItem } from 'utils/localStorage' ; type Props = { pendingWallet : AbstractConnector ; userFriendlyWalletName : string ; setDetectedError : ( error : Web3Error ) => void ; } ; function AuthenticateWalletPendingGnosisSafe ( { pendingWallet , userFriendlyWalletName , setDetectedError , } ) { const { library , account } = useWeb3React < Web3Provider > ( ) ; const [ pendingState , setPendingState ] = useState < PendingState > ( INITIAL ) ; const fetcher = useFetcher ( ) ; const { logIn } = useAuthActions ( ) ; const previousAttemptNonce = useMemo ( ( ) => getLocalStorageItem ( GNOSIS_NONCE_STORAGE_KEY ) , [ ] ) ; const [ nonce , setNonce ] = useState ( '' ) ; const [ userExists , setUserExists ] = useState ( false ) ; const authenticateWithBackend = useCallback ( async ( address , nonce ) => { const payload = { address , wallet_type : GNOSIS_SAFE_WALLET_TYPE_ID , nonce , } ; const { jwt , userId } = await loginOrCreateUser ( userExists , payload , fetcher ) ; window . localStorage . removeItem ( GNOSIS_NONCE_STORAGE_KEY ) ; Mixpanel . trackConnectWallet ( userFriendlyWalletName , 'Sign In' ) ; logIn ( { jwt , userId } , address ) ; } , [ fetcher , logIn , userExists , userFriendlyWalletName ] ) ; const handleError = useCallback ( ( error ) => { if ( isWeb3Error ( error ) ) { setDetectedError ( error ) ; } if ( error instanceof Error ) { const web3Error = { code : 'AUTHENTICATION_ERROR' , ... error } ; setDetectedError ( web3Error ) ; } } , [ setDetectedError ] ) ; const [ authenticationFlowStarted , setAuthenticationFlowStarted ] = useState ( false ) ; const attemptAuthentication = useCallback ( async ( address , nonce ) => { try { setPendingState ( PROMPT_SIGNATURE ) ; await signMessageWithContractAccount ( address , nonce , pendingWallet , library ) ; window . localStorage . setItem ( GNOSIS_NONCE_STORAGE_KEY , JSON . stringify ( nonce ) ) ; setPendingState ( LISTENING_ONCHAIN ) ; await listenForGnosisSignature ( address , nonce , library ) ; await authenticateWithBackend ( address , nonce ) ; } catch ( error ) { console . error ( error ) ; handleError ( error ) ; } } , [ authenticateWithBackend , handleError , library , pendingWallet ] ) ; const manuallyValidateSignature = useCallback ( async ( ) => { if ( ! account ) { return ; } try { const wasSigned = await validateNonceSignedByGnosis ( account , nonce , library ) ; if ( wasSigned ) { await authenticateWithBackend ( account , nonce ) ; } if ( pendingState !== LISTENING_ONCHAIN ) { setPendingState ( LISTENING_ONCHAIN ) ; await listenForGnosisSignature ( account , nonce , library ) ; void authenticateWithBackend ( account , nonce ) ; } } catch ( error ) { handleError ( error ) ; } } , [ account , authenticateWithBackend , handleError , library , nonce , pendingState ] ) ; const restartAuthentication = useCallback ( async ( ) => { if ( account ) { await attemptAuthentication ( account . toLowerCase ( ) , nonce ) ; } } , [ account , attemptAuthentication , nonce ] ) ; useEffect ( ( ) => { if ( authenticationFlowStarted ) { return ; } async function initiateAuthentication ( ) { if ( account ) { setAuthenticationFlowStarted ( true ) ; try { const { nonce , user_exists : userExists } = await fetchNonce ( account , fetcher ) ; setNonce ( nonce ) ; setUserExists ( userExists ) ; if ( nonce === previousAttemptNonce ) { return ; } await attemptAuthentication ( account . toLowerCase ( ) , nonce ) ; } catch ( error ) { handleError ( error ) ; } } } void initiateAuthentication ( ) ; } , [ account , attemptAuthentication , authenticationFlowStarted , fetcher , handleError , previousAttemptNonce , ] ) ; return ( < GnosisSafePendingMessage pendingState = { pendingState } userFriendlyWalletName = { userFriendlyWalletName } onRestartClick = { restartAuthentication } manuallyValidateSignature = { manuallyValidateSignature } / > ) ; } export default AuthenticateWalletPendingGnosisSafe ;