import { useSignMessage } from "wagmi" import { DefaultError, MutationOptions, useMutation, } from "@tanstack/react-query" import { useCreateAccount } from "./useCreateAccount" import { useCreateSession } from "./useCreateSession" import { useEnsureNoSessionAndFetchNonce } from "./useEnsureNoSessionAndFetchNonce" import { createSignInWithWalletMessage, verifyDomainInSignInWithWalletMessage, } from "../utils/siww" import { useGetAccountByAddress } from "./useGetAccountByAddress" import type { Session } from "../api" import { useWalletAccount } from "./useWalletAccount" function useAuthenticateWithWallet( shouldCreateAccount = false, mutationOptions: Omit< MutationOptions, "mutationFn" | "mutationKey" > = {}, ) { const walletAccount = useWalletAccount() const { ensureNoSessionAndFetchNonce } = useEnsureNoSessionAndFetchNonce() const { createSessionAsync } = useCreateSession() const { createAccountAsync } = useCreateAccount() const { signMessageAsync } = useSignMessage() const { refetch: getAccountByAddress } = useGetAccountByAddress( walletAccount.walletAddress, { enabled: false, retry: false, }, ) const { mutate, mutateAsync, ...signInMutationRestParameters } = useMutation({ mutationFn: async (chainId?: number | void) => { if (!walletAccount.walletAddress) { throw new Error("Sign in error: Wallet not connected!") } const nonce = await ensureNoSessionAndFetchNonce() const messageResult = createSignInWithWalletMessage( walletAccount.walletAddress, nonce, walletAccount.networkFamily!, chainId ?? walletAccount.chainId, ) const signatureResult = await signMessageAsync({ message: messageResult, connector: walletAccount.connector, }) await verifyDomainInSignInWithWalletMessage( messageResult, signatureResult, nonce, ) if (shouldCreateAccount) { const getAccountByAddressResult = await getAccountByAddress() if (getAccountByAddressResult.data) { throw new Error( "Wallet authentication failed: Account creation failed. Account already exists.", ) } if (getAccountByAddressResult.error) { throw new Error( `Wallet authentication failed: Account creation failed. Could not verify if account already exists: ${getAccountByAddressResult.error}`, ) } // Fetch was successful, but no account was found try { const createAccountResult = await createAccountAsync({ type: "wallet", message: messageResult, signature: signatureResult, }) if (!createAccountResult) { throw new Error("Failed to create new account") } } catch (error) { throw new Error( `Wallet authentication failed: Account creation failed: ${error}`, ) } } return (await createSessionAsync({ type: "wallet", message: messageResult, signature: signatureResult, })) as Session // ^ By passing type: "wallet" we know for sure the return type is Session }, ...mutationOptions, }) return { authenticateWithWallet: mutate, authenticateWithWalletAsync: mutateAsync, ...signInMutationRestParameters, } } export { useAuthenticateWithWallet }