diff --git a/tools/walletextension/frontend/src/api/ethRequests.ts b/tools/walletextension/frontend/src/api/ethRequests.ts index b4ba8ed933..a975518ea1 100644 --- a/tools/walletextension/frontend/src/api/ethRequests.ts +++ b/tools/walletextension/frontend/src/api/ethRequests.ts @@ -3,13 +3,19 @@ import { tenChainIDDecimal, tenChainIDHex, tenscanLink, + userStorageAddress, } from "@/lib/constants"; -import { getNetworkName, getRandomIntAsString, isTenChain } from "@/lib/utils"; +import { + getNetworkName, + getRandomIntAsString, + isTenChain, + ethereum, +} from "@/lib/utils"; import { requestMethods } from "@/routes"; import { ethers } from "ethers"; import { accountIsAuthenticated, authenticateUser } from "./gateway"; - -const { ethereum } = typeof window !== "undefined" ? window : ({} as any); +import { showToast } from "@/components/ui/use-toast"; +import { ToastType } from "@/types/interfaces"; const typedData = { types: { @@ -73,13 +79,17 @@ export const getSignature = async (account: string, data: any) => { export const getUserID = async (provider: ethers.providers.Web3Provider) => { if (!provider) { + showToast( + ToastType.DESTRUCTIVE, + "No provider found. Please try again later." + ); return null; } try { if (await isTenChain()) { const id = await provider.send(requestMethods.getStorageAt, [ - "getUserID", + userStorageAddress, getRandomIntAsString(0, 1000), null, ]); @@ -122,8 +132,10 @@ export async function authenticateAccountWithTenGatewayEIP712( account: string ): Promise { if (!userID) { + showToast(ToastType.INFO, "User ID is required to revoke accounts"); return; } + try { const isAuthenticated = await accountIsAuthenticated(userID, account); if (isAuthenticated.status) { diff --git a/tools/walletextension/frontend/src/components/providers/wallet-provider.tsx b/tools/walletextension/frontend/src/components/providers/wallet-provider.tsx index 27110522ac..3678d767c1 100644 --- a/tools/walletextension/frontend/src/components/providers/wallet-provider.tsx +++ b/tools/walletextension/frontend/src/components/providers/wallet-provider.tsx @@ -5,7 +5,7 @@ import { Account, } from "../../types/interfaces/WalletInterfaces"; import { showToast } from "../ui/use-toast"; -import { isValidUserIDFormat } from "../../lib/utils"; +import { ethereum } from "../../lib/utils"; import { accountIsAuthenticated, fetchVersion, @@ -19,8 +19,6 @@ import { import { ethers } from "ethers"; import ethService from "@/services/ethService"; -const { ethereum } = typeof window !== "undefined" ? window : ({} as any); - const WalletConnectionContext = createContext(null); @@ -46,16 +44,7 @@ export const WalletConnectionProvider = ({ const [provider, setProvider] = useState({} as ethers.providers.Web3Provider); useEffect(() => { - const handleAccountsChanged = async () => { - if (!ethereum) { - return; - } - if (userID && isValidUserIDFormat(userID)) { - const status = - await ethService.getCorrectScreenBasedOnMetamaskAndUserID(userID); - setWalletConnected(status); - } - }; + initialize(); ethereum.on("accountsChanged", handleAccountsChanged); return () => { @@ -64,29 +53,30 @@ export const WalletConnectionProvider = ({ // eslint-disable-next-line react-hooks/exhaustive-deps }, []); + const handleAccountsChanged = async () => { + if (!ethereum) { + return; + } + const status = await ethService.isUserConnectedToTenChain(userID); + setWalletConnected(status); + }; + const initialize = async () => { const providerInstance = new ethers.providers.Web3Provider(ethereum); setProvider(providerInstance); await ethService.checkIfMetamaskIsLoaded(providerInstance); const id = await getUserID(providerInstance); setUserID(id); - const status = await ethService.getCorrectScreenBasedOnMetamaskAndUserID( - id - ); - setWalletConnected(status); + handleAccountsChanged(); const accounts = await ethService.getAccounts(providerInstance); setAccounts(accounts || null); setVersion(await fetchVersion()); setLoading(false); }; - useEffect(() => { - initialize(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - const connectAccount = async (account: string) => { if (!userID) { + showToast(ToastType.INFO, "User ID is required to connect an account."); return; } await authenticateAccountWithTenGatewayEIP712(userID, account); @@ -114,6 +104,7 @@ export const WalletConnectionProvider = ({ const revokeAccounts = async () => { if (!userID) { + showToast(ToastType.INFO, "User ID is required to revoke accounts"); return; } const revokeResponse = await revokeAccountsApi(userID); diff --git a/tools/walletextension/frontend/src/lib/constants.ts b/tools/walletextension/frontend/src/lib/constants.ts index 4f7eacdc0c..5b582a40dd 100644 --- a/tools/walletextension/frontend/src/lib/constants.ts +++ b/tools/walletextension/frontend/src/lib/constants.ts @@ -41,6 +41,8 @@ export const tenChainIDDecimal = 443; export const tenChainIDHex = "0x" + tenChainIDDecimal.toString(16); // Convert to hexadecimal and prefix with '0x' export const METAMASK_CONNECTION_TIMEOUT = 3000; +export const userStorageAddress = "getUserID"; + export const nativeCurrency = { name: "Sepolia Ether", symbol: "ETH", diff --git a/tools/walletextension/frontend/src/lib/utils.ts b/tools/walletextension/frontend/src/lib/utils.ts index da06818815..a13f5f2cea 100644 --- a/tools/walletextension/frontend/src/lib/utils.ts +++ b/tools/walletextension/frontend/src/lib/utils.ts @@ -55,8 +55,11 @@ export function getRPCFromUrl() { } export async function isTenChain() { - let currentChain = await (window as any).ethereum.request({ + let currentChain = await ethereum.request({ method: "eth_chainId", }); return currentChain === tenChainIDHex; } + +export const { ethereum } = + typeof window !== "undefined" ? window : ({} as any); diff --git a/tools/walletextension/frontend/src/services/ethService.ts b/tools/walletextension/frontend/src/services/ethService.ts index a27865e1e2..da1c3ce780 100644 --- a/tools/walletextension/frontend/src/services/ethService.ts +++ b/tools/walletextension/frontend/src/services/ethService.ts @@ -5,13 +5,11 @@ import { import { accountIsAuthenticated } from "@/api/gateway"; import { showToast } from "@/components/ui/use-toast"; import { METAMASK_CONNECTION_TIMEOUT } from "@/lib/constants"; -import { isTenChain, isValidUserIDFormat } from "@/lib/utils"; +import { isTenChain, isValidUserIDFormat, ethereum } from "@/lib/utils"; import { ToastType } from "@/types/interfaces"; import { Account } from "@/types/interfaces/WalletInterfaces"; import { ethers } from "ethers"; -const { ethereum } = typeof window !== "undefined" ? window : ({} as any); - const ethService = { checkIfMetamaskIsLoaded: async (provider: ethers.providers.Web3Provider) => { if (ethereum) { @@ -19,15 +17,23 @@ const ethService = { } else { showToast(ToastType.INFO, "Connecting to MetaMask..."); + let timeoutId: ReturnType; const handleEthereumOnce = () => { ethService.handleEthereum(provider); }; - window.addEventListener("ethereum#initialized", handleEthereumOnce, { - once: true, - }); + window.addEventListener( + "ethereum#initialized", + () => { + clearTimeout(timeoutId); + handleEthereumOnce(); + }, + { + once: true, + } + ); - setTimeout(() => { + timeoutId = setTimeout(() => { handleEthereumOnce(); // Call the handler function after the timeout }, METAMASK_CONNECTION_TIMEOUT); } @@ -65,7 +71,7 @@ const ethService = { } }, - getCorrectScreenBasedOnMetamaskAndUserID: async (userID: string) => { + isUserConnectedToTenChain: async (userID: string) => { if (await isTenChain()) { if (userID && isValidUserIDFormat(userID)) { return true; @@ -78,20 +84,25 @@ const ethService = { }, getAccounts: async (provider: ethers.providers.Web3Provider) => { + if (!provider) { + showToast( + ToastType.DESTRUCTIVE, + "No provider found. Please try again later." + ); + return; + } + const id = await getUserID(provider); + if (!id || !isValidUserIDFormat(id)) { + showToast( + ToastType.DESTRUCTIVE, + "No user ID found. Please try again later." + ); return; } try { - if (!provider) { - showToast( - ToastType.DESTRUCTIVE, - "No provider found. Please try again later." - ); - return; - } - showToast(ToastType.INFO, "Getting accounts..."); if (!(await isTenChain())) { @@ -108,15 +119,15 @@ const ethService = { let updatedAccounts: Account[] = []; - for (let i = 0; i < accounts.length; i++) { - const account = accounts[i]; - await authenticateAccountWithTenGatewayEIP712(id, account); - const { status } = await accountIsAuthenticated(id, account); - updatedAccounts.push({ - name: account, - connected: status, - }); - } + const authenticationPromises = accounts.map((account) => + authenticateAccountWithTenGatewayEIP712(id, account) + .then(() => accountIsAuthenticated(id, account)) + .then(({ status }) => ({ + name: account, + connected: status, + })) + ); + updatedAccounts = await Promise.all(authenticationPromises); showToast(ToastType.SUCCESS, "Accounts fetched successfully."); return updatedAccounts; } catch (error) {