From 629ef814bf19e944cc7ab7a7c7cc70b8b89188ae Mon Sep 17 00:00:00 2001 From: Florin Dzeladini Date: Thu, 23 May 2024 09:55:29 +0200 Subject: [PATCH 01/12] feat: add development mode to use local served remoteEntry.js from starknet-snap repo --- example/package.json | 3 ++- package.json | 1 + packages/core/package.json | 8 +++++--- packages/core/src/wallet/metamaskBridge.ts | 10 ++++++++-- packages/ui/package.json | 3 ++- 5 files changed, 18 insertions(+), 7 deletions(-) diff --git a/example/package.json b/example/package.json index e9d1b6b..a5093e1 100644 --- a/example/package.json +++ b/example/package.json @@ -6,7 +6,8 @@ "scripts": { "build": "vite build", "dev": "vite", - "preview": "vite preview" + "preview": "vite preview", + "prod": "vite" }, "dependencies": { "get-starknet": "workspace:^3.0.1", diff --git a/package.json b/package.json index 42d301c..60f1ff2 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "format": "prettier --ignore-path .gitignore --plugin-search-dir=. --write '**/*.{js,cjs,ts,tsx,svelte,md,yml,json}'", "format:check": "prettier --ignore-path .gitignore --plugin-search-dir=. --check '**/*.{js,cjs,ts,tsx,svelte,md,yml,json}'", "prepare": "pnpm run build && husky install", + "prod": "pnpm run -r --parallel prod", "publish": "pnpm publish -r --no-git-checks", "test": "CI=true pnpm run -r test", "version": "changeset version && pnpm install --lockfile-only" diff --git a/packages/core/package.json b/packages/core/package.json index 2b531e6..378d44a 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -25,12 +25,14 @@ "dist" ], "scripts": { - "build": "vite build", - "dev": "vite build --watch", + "build": "vite build --mode production", + "dev": "vite build --watch --mode development", + "prod": "vite build --watch --mode production", "test": "vitest" }, "dependencies": { - "@module-federation/runtime": "^0.1.2" + "@module-federation/runtime": "^0.1.2", + "dotenv": "^16.4.5" }, "devDependencies": { "c8": "^7.12.0", diff --git a/packages/core/src/wallet/metamaskBridge.ts b/packages/core/src/wallet/metamaskBridge.ts index 6462f58..ae682da 100644 --- a/packages/core/src/wallet/metamaskBridge.ts +++ b/packages/core/src/wallet/metamaskBridge.ts @@ -7,6 +7,13 @@ import type { import wallets, { WalletProvider } from "../discovery" import { init, loadRemote } from "@module-federation/runtime" +const remoteEntryUrl = + import.meta.env.MODE === "development" + ? "http://localhost:8082/remoteEntry.js" + : "https://snaps.consensys.io/starknet/get-starknet/v1/remoteEntry.js" + +console.log(remoteEntryUrl) + interface MetaMaskProvider { isMetaMask: boolean request(options: { method: string }): Promise @@ -130,8 +137,7 @@ function createMetaMaskProviderWrapper( { name: "MetaMaskStarknetSnapWallet", alias: "MetaMaskStarknetSnapWallet", - entry: - "https://snaps.consensys.io/starknet/get-starknet/v1/remoteEntry.js", + entry: remoteEntryUrl, }, ], }) diff --git a/packages/ui/package.json b/packages/ui/package.json index a0a2397..aefe3c9 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -27,7 +27,8 @@ "scripts": { "build": "vite build", "check": "svelte-check --tsconfig ./tsconfig.json", - "dev": "vite build --watch" + "dev": "vite build --watch", + "prod": "vite build --watch" }, "dependencies": { "bowser": "^2.11.0", From 0a088d5c8843c08e27f483feb85aa9de8943a644 Mon Sep 17 00:00:00 2001 From: Florin Dzeladini Date: Thu, 23 May 2024 15:44:17 +0200 Subject: [PATCH 02/12] feat: metamask detection follows eip-6963 --- packages/core/src/wallet/metamaskBridge.ts | 50 ++++++++++------------ 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/packages/core/src/wallet/metamaskBridge.ts b/packages/core/src/wallet/metamaskBridge.ts index ae682da..526a47f 100644 --- a/packages/core/src/wallet/metamaskBridge.ts +++ b/packages/core/src/wallet/metamaskBridge.ts @@ -12,8 +12,6 @@ const remoteEntryUrl = ? "http://localhost:8082/remoteEntry.js" : "https://snaps.consensys.io/starknet/get-starknet/v1/remoteEntry.js" -console.log(remoteEntryUrl) - interface MetaMaskProvider { isMetaMask: boolean request(options: { method: string }): Promise @@ -31,36 +29,34 @@ function isMetaMaskProvider(obj: unknown): obj is MetaMaskProvider { function detectMetaMaskProvider( windowObject: Record, { timeout = 3000 } = {}, -) { - let handled = false +): Promise { return new Promise((resolve) => { - if (windowObject.ethereum) { - handleEthereum() - } else { - if (typeof windowObject.addEventListener === "function") { - windowObject.addEventListener("ethereum#initialized", handleEthereum, { - once: true, - }) + let handled = false + + const handleEIP6963Provider = (event: CustomEvent) => { + const { provider } = event.detail + if (isMetaMaskProvider(provider)) { + resolve(provider) + handled = true } - setTimeout(() => { - handleEthereum() - }, timeout) } - function handleEthereum() { - if (handled) { - return - } - handled = true - if (typeof windowObject.removeEventListener === "function") { - windowObject.removeEventListener("ethereum#initialized", handleEthereum) - } - const { ethereum } = windowObject - if (isMetaMaskProvider(ethereum)) { - resolve(ethereum) - } else { + + if (typeof windowObject.addEventListener === "function") { + windowObject.addEventListener( + "eip6963:announceProvider", + handleEIP6963Provider, + { once: true }, + ) + } + + setTimeout(() => { + if (!handled) { resolve(null) } - } + }, timeout) + + // Notify event listeners and other parts of the dapp that a provider is requested. + windowObject.dispatchEvent(new Event("eip6963:requestProvider")) }) } From b728397ded5e3f6a8cce0615030dd2f3ab65e044 Mon Sep 17 00:00:00 2001 From: Florin Dzeladini Date: Fri, 24 May 2024 09:06:01 +0200 Subject: [PATCH 03/12] chore: remoteEntry.js url can be controlled with env VITE_MM_FED_URL --- example/package.json | 3 +-- package.json | 1 - packages/core/.env.sample | 1 + packages/core/package.json | 8 +++----- packages/core/src/wallet/metamaskBridge.ts | 5 ++--- 5 files changed, 7 insertions(+), 11 deletions(-) create mode 100644 packages/core/.env.sample diff --git a/example/package.json b/example/package.json index a5093e1..e9d1b6b 100644 --- a/example/package.json +++ b/example/package.json @@ -6,8 +6,7 @@ "scripts": { "build": "vite build", "dev": "vite", - "preview": "vite preview", - "prod": "vite" + "preview": "vite preview" }, "dependencies": { "get-starknet": "workspace:^3.0.1", diff --git a/package.json b/package.json index 60f1ff2..42d301c 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,6 @@ "format": "prettier --ignore-path .gitignore --plugin-search-dir=. --write '**/*.{js,cjs,ts,tsx,svelte,md,yml,json}'", "format:check": "prettier --ignore-path .gitignore --plugin-search-dir=. --check '**/*.{js,cjs,ts,tsx,svelte,md,yml,json}'", "prepare": "pnpm run build && husky install", - "prod": "pnpm run -r --parallel prod", "publish": "pnpm publish -r --no-git-checks", "test": "CI=true pnpm run -r test", "version": "changeset version && pnpm install --lockfile-only" diff --git a/packages/core/.env.sample b/packages/core/.env.sample new file mode 100644 index 0000000..5c5e935 --- /dev/null +++ b/packages/core/.env.sample @@ -0,0 +1 @@ +VITE_MM_FED_URL=http://localhost:8082/remoteEntry.js diff --git a/packages/core/package.json b/packages/core/package.json index 378d44a..2b531e6 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -25,14 +25,12 @@ "dist" ], "scripts": { - "build": "vite build --mode production", - "dev": "vite build --watch --mode development", - "prod": "vite build --watch --mode production", + "build": "vite build", + "dev": "vite build --watch", "test": "vitest" }, "dependencies": { - "@module-federation/runtime": "^0.1.2", - "dotenv": "^16.4.5" + "@module-federation/runtime": "^0.1.2" }, "devDependencies": { "c8": "^7.12.0", diff --git a/packages/core/src/wallet/metamaskBridge.ts b/packages/core/src/wallet/metamaskBridge.ts index 526a47f..2edcb5d 100644 --- a/packages/core/src/wallet/metamaskBridge.ts +++ b/packages/core/src/wallet/metamaskBridge.ts @@ -8,9 +8,8 @@ import wallets, { WalletProvider } from "../discovery" import { init, loadRemote } from "@module-federation/runtime" const remoteEntryUrl = - import.meta.env.MODE === "development" - ? "http://localhost:8082/remoteEntry.js" - : "https://snaps.consensys.io/starknet/get-starknet/v1/remoteEntry.js" + import.meta.env.VITE_MM_FED_URL ?? + "https://snaps.consensys.io/starknet/get-starknet/v1/remoteEntry.js" interface MetaMaskProvider { isMetaMask: boolean From cb148d45d4023e89b0b888716a4036a8e4f5903c Mon Sep 17 00:00:00 2001 From: Florin Dzeladini Date: Fri, 24 May 2024 10:48:26 +0200 Subject: [PATCH 04/12] chore: removing unecessary prod script in package.json --- packages/ui/package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/ui/package.json b/packages/ui/package.json index aefe3c9..a0a2397 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -27,8 +27,7 @@ "scripts": { "build": "vite build", "check": "svelte-check --tsconfig ./tsconfig.json", - "dev": "vite build --watch", - "prod": "vite build --watch" + "dev": "vite build --watch" }, "dependencies": { "bowser": "^2.11.0", From a843c67f59d9d5e67bcd8838bb054e7fe31a7833 Mon Sep 17 00:00:00 2001 From: Florin Dzeladini Date: Mon, 27 May 2024 09:40:08 +0200 Subject: [PATCH 05/12] fix: handled variable misplaced in detectMetaMaskProvider --- packages/core/src/wallet/metamaskBridge.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/core/src/wallet/metamaskBridge.ts b/packages/core/src/wallet/metamaskBridge.ts index 2edcb5d..67f22e7 100644 --- a/packages/core/src/wallet/metamaskBridge.ts +++ b/packages/core/src/wallet/metamaskBridge.ts @@ -29,9 +29,8 @@ function detectMetaMaskProvider( windowObject: Record, { timeout = 3000 } = {}, ): Promise { + let handled = false return new Promise((resolve) => { - let handled = false - const handleEIP6963Provider = (event: CustomEvent) => { const { provider } = event.detail if (isMetaMaskProvider(provider)) { From 1dfd0638d4aff97b571f4b14368dbb9173adfb3e Mon Sep 17 00:00:00 2001 From: Florin Dzeladini Date: Mon, 27 May 2024 10:23:57 +0200 Subject: [PATCH 06/12] fix: rdns check for metamask wallet discovery --- packages/core/src/wallet/metamaskBridge.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/core/src/wallet/metamaskBridge.ts b/packages/core/src/wallet/metamaskBridge.ts index 67f22e7..cfb3ad9 100644 --- a/packages/core/src/wallet/metamaskBridge.ts +++ b/packages/core/src/wallet/metamaskBridge.ts @@ -33,7 +33,10 @@ function detectMetaMaskProvider( return new Promise((resolve) => { const handleEIP6963Provider = (event: CustomEvent) => { const { provider } = event.detail - if (isMetaMaskProvider(provider)) { + const { info } = event.detail + const rdnsCheck = + info.rdns === "io.metamask" || info.rdns === "io.metamask.flask" + if (rdnsCheck && isMetaMaskProvider(provider)) { resolve(provider) handled = true } @@ -43,7 +46,6 @@ function detectMetaMaskProvider( windowObject.addEventListener( "eip6963:announceProvider", handleEIP6963Provider, - { once: true }, ) } From 617cb76789162170436830e9556038280aaccf6a Mon Sep 17 00:00:00 2001 From: Florin Dzeladini Date: Mon, 27 May 2024 10:53:03 +0200 Subject: [PATCH 07/12] chore: type checking and code formatting --- packages/core/src/wallet/metamaskBridge.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/core/src/wallet/metamaskBridge.ts b/packages/core/src/wallet/metamaskBridge.ts index cfb3ad9..cc60275 100644 --- a/packages/core/src/wallet/metamaskBridge.ts +++ b/packages/core/src/wallet/metamaskBridge.ts @@ -32,8 +32,7 @@ function detectMetaMaskProvider( let handled = false return new Promise((resolve) => { const handleEIP6963Provider = (event: CustomEvent) => { - const { provider } = event.detail - const { info } = event.detail + const { info, provider } = event.detail const rdnsCheck = info.rdns === "io.metamask" || info.rdns === "io.metamask.flask" if (rdnsCheck && isMetaMaskProvider(provider)) { @@ -56,7 +55,9 @@ function detectMetaMaskProvider( }, timeout) // Notify event listeners and other parts of the dapp that a provider is requested. - windowObject.dispatchEvent(new Event("eip6963:requestProvider")) + if (typeof windowObject.dispatchEvent === "function") { + windowObject.dispatchEvent(new Event("eip6963:requestProvider")) + } }) } From fc0cf6569822b53ccc6f91fb3047867752e85a65 Mon Sep 17 00:00:00 2001 From: bluecco Date: Mon, 6 May 2024 15:11:25 +0200 Subject: [PATCH 08/12] fix: use windowObject instead of window to prevent ssr breaking --- packages/core/src/wallet/metamaskBridge.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/wallet/metamaskBridge.ts b/packages/core/src/wallet/metamaskBridge.ts index cc60275..88b16d6 100644 --- a/packages/core/src/wallet/metamaskBridge.ts +++ b/packages/core/src/wallet/metamaskBridge.ts @@ -177,7 +177,7 @@ function createMetaMaskProviderWrapper( } async function injectMetamaskBridge(windowObject: Record) { - if (window.hasOwnProperty("starknet_metamask")) { + if (windowObject.hasOwnProperty("starknet_metamask")) { return } From f50efde71ce262c0143ecf1692771a56b1010848 Mon Sep 17 00:00:00 2001 From: Florin Dzeladini Date: Mon, 24 Jun 2024 12:06:05 +0200 Subject: [PATCH 09/12] fix: removed .env.sample --- packages/core/.env.sample | 1 - packages/core/src/wallet/metamaskBridge.ts | 9 +++------ 2 files changed, 3 insertions(+), 7 deletions(-) delete mode 100644 packages/core/.env.sample diff --git a/packages/core/.env.sample b/packages/core/.env.sample deleted file mode 100644 index 5c5e935..0000000 --- a/packages/core/.env.sample +++ /dev/null @@ -1 +0,0 @@ -VITE_MM_FED_URL=http://localhost:8082/remoteEntry.js diff --git a/packages/core/src/wallet/metamaskBridge.ts b/packages/core/src/wallet/metamaskBridge.ts index 88b16d6..101cf84 100644 --- a/packages/core/src/wallet/metamaskBridge.ts +++ b/packages/core/src/wallet/metamaskBridge.ts @@ -7,10 +7,6 @@ import type { import wallets, { WalletProvider } from "../discovery" import { init, loadRemote } from "@module-federation/runtime" -const remoteEntryUrl = - import.meta.env.VITE_MM_FED_URL ?? - "https://snaps.consensys.io/starknet/get-starknet/v1/remoteEntry.js" - interface MetaMaskProvider { isMetaMask: boolean request(options: { method: string }): Promise @@ -134,7 +130,8 @@ function createMetaMaskProviderWrapper( { name: "MetaMaskStarknetSnapWallet", alias: "MetaMaskStarknetSnapWallet", - entry: remoteEntryUrl, + entry: + "https://snaps.consensys.io/starknet/get-starknet/v1/remoteEntry.js", }, ], }) @@ -191,7 +188,7 @@ async function injectMetamaskBridge(windowObject: Record) { return } - window.starknet_metamask = createMetaMaskProviderWrapper( + windowObject.starknet_metamask = createMetaMaskProviderWrapper( metamaskWalletInfo, provider, ) From 3ea449e29a99bbda587adf6fe2a66557ba219641 Mon Sep 17 00:00:00 2001 From: Florin Dzeladini Date: Fri, 28 Jun 2024 15:21:42 +0200 Subject: [PATCH 10/12] fix: removedMetaMask specifics provider detection --- packages/core/src/wallet/metamaskBridge.ts | 152 ++++++--------------- 1 file changed, 45 insertions(+), 107 deletions(-) diff --git a/packages/core/src/wallet/metamaskBridge.ts b/packages/core/src/wallet/metamaskBridge.ts index 101cf84..6c82575 100644 --- a/packages/core/src/wallet/metamaskBridge.ts +++ b/packages/core/src/wallet/metamaskBridge.ts @@ -7,91 +7,12 @@ import type { import wallets, { WalletProvider } from "../discovery" import { init, loadRemote } from "@module-federation/runtime" -interface MetaMaskProvider { - isMetaMask: boolean - request(options: { method: string }): Promise -} - -function isMetaMaskProvider(obj: unknown): obj is MetaMaskProvider { - return ( - obj !== null && - typeof obj === "object" && - obj.hasOwnProperty("isMetaMask") && - obj.hasOwnProperty("request") - ) -} - -function detectMetaMaskProvider( - windowObject: Record, - { timeout = 3000 } = {}, -): Promise { - let handled = false - return new Promise((resolve) => { - const handleEIP6963Provider = (event: CustomEvent) => { - const { info, provider } = event.detail - const rdnsCheck = - info.rdns === "io.metamask" || info.rdns === "io.metamask.flask" - if (rdnsCheck && isMetaMaskProvider(provider)) { - resolve(provider) - handled = true - } - } - - if (typeof windowObject.addEventListener === "function") { - windowObject.addEventListener( - "eip6963:announceProvider", - handleEIP6963Provider, - ) - } - - setTimeout(() => { - if (!handled) { - resolve(null) - } - }, timeout) - - // Notify event listeners and other parts of the dapp that a provider is requested. - if (typeof windowObject.dispatchEvent === "function") { - windowObject.dispatchEvent(new Event("eip6963:requestProvider")) - } - }) -} - -async function waitForMetaMaskProvider( - windowObject: Record, - options: { timeout?: number; retries?: number } = {}, -): Promise { - const { timeout = 3000, retries = 0 } = options - - let provider: MetaMaskProvider | null = null - try { - provider = await detectMetaMaskProvider(windowObject, { timeout }) - } catch { - // Silent error - do nothing - } - - if (provider) { - return provider - } - - if (retries === 0) { - return null - } - - provider = await waitForMetaMaskProvider({ timeout, retries: retries - 1 }) - return provider -} - -async function detectMetamaskSupport(windowObject: Record) { - const provider = await waitForMetaMaskProvider(windowObject, { retries: 3 }) - return provider -} - function createMetaMaskProviderWrapper( walletInfo: WalletProvider, - provider: unknown, + windowObject: Record, ): StarknetWindowObject { let metaMaskSnapWallet: IStarknetWindowObject | undefined + let isEnabling = false const metaMaskProviderWrapper: IStarknetWindowObject = { id: walletInfo.id, name: walletInfo.name, @@ -123,30 +44,52 @@ function createMetaMaskProviderWrapper( return metaMaskSnapWallet.request(call) }, async enable(): Promise { - if (!metaMaskSnapWallet) { - await init({ - name: "MetaMaskStarknetSnapWallet", - remotes: [ - { - name: "MetaMaskStarknetSnapWallet", - alias: "MetaMaskStarknetSnapWallet", - entry: - "https://snaps.consensys.io/starknet/get-starknet/v1/remoteEntry.js", - }, - ], + if (isEnabling) { + // If enable is already being called, return a promise that waits for the current enable call to finish + return new Promise((resolve, reject) => { + const checkInterval = setInterval(() => { + if (!isEnabling) { + clearInterval(checkInterval) + if (metaMaskSnapWallet) { + resolve(metaMaskSnapWallet.enable()) + } else { + reject(new Error("Wallet not enabled")) + } + } + }, 100) }) - - const result = await loadRemote("MetaMaskStarknetSnapWallet/index") - - const { MetaMaskSnapWallet } = result as { - MetaMaskSnapWallet: any - MetaMaskSnap: any + } + isEnabling = true // Set the guard flag + try { + if (!metaMaskSnapWallet) { + await init({ + name: "MetaMaskStarknetSnapWallet", + remotes: [ + { + name: "MetaMaskStarknetSnapWallet", + alias: "MetaMaskStarknetSnapWallet", + entry: + "https://snaps.consensys.io/starknet/get-starknet/v1/remoteEntry.js", //"http://localhost:8082/remoteEntry.js", + }, + ], + }) + + const result = await loadRemote("MetaMaskStarknetSnapWallet/index") + + const { MetaMaskSnapWallet } = result as { + MetaMaskSnapWallet: any + MetaMaskSnap: any + } + + metaMaskSnapWallet = new MetaMaskSnapWallet("*") + await (metaMaskSnapWallet as any).init(windowObject) } - metaMaskSnapWallet = new MetaMaskSnapWallet(provider, "*") + const accounts = await metaMaskSnapWallet!.enable() + return accounts + } finally { + isEnabling = false // Reset the guard flag } - - return await metaMaskSnapWallet!.enable() }, isPreauthorized() { return metaMaskSnapWallet?.isPreauthorized() ?? Promise.resolve(false) @@ -183,14 +126,9 @@ async function injectMetamaskBridge(windowObject: Record) { return } - const provider = await detectMetamaskSupport(windowObject) - if (!provider) { - return - } - windowObject.starknet_metamask = createMetaMaskProviderWrapper( metamaskWalletInfo, - provider, + windowObject, ) } From a06fc01f448f5a05aba24a7dc72dab416f407e95 Mon Sep 17 00:00:00 2001 From: Florin Dzeladini Date: Tue, 2 Jul 2024 09:59:27 +0200 Subject: [PATCH 11/12] feat: remove isEnabled check and use fetchMetaMaskSnapWallet helper function --- packages/core/src/wallet/metamaskBridge.ts | 76 +++++++++------------- 1 file changed, 31 insertions(+), 45 deletions(-) diff --git a/packages/core/src/wallet/metamaskBridge.ts b/packages/core/src/wallet/metamaskBridge.ts index 6c82575..63375d4 100644 --- a/packages/core/src/wallet/metamaskBridge.ts +++ b/packages/core/src/wallet/metamaskBridge.ts @@ -7,12 +7,37 @@ import type { import wallets, { WalletProvider } from "../discovery" import { init, loadRemote } from "@module-federation/runtime" +async function fetchMetaMaskSnapWallet(windowObject: Record) { + await init({ + name: "MetaMaskStarknetSnapWallet", + remotes: [ + { + name: "MetaMaskStarknetSnapWallet", + alias: "MetaMaskStarknetSnapWallet", + entry: + "https://snaps.consensys.io/starknet/get-starknet/v1/remoteEntry.js", //"http://localhost:8082/remoteEntry.js", + }, + ], + }) + + const result = await loadRemote("MetaMaskStarknetSnapWallet/index") + + const { MetaMaskSnapWallet } = result as { + MetaMaskSnapWallet: any + MetaMaskSnap: any + } + + const metaMaskSnapWallet = new MetaMaskSnapWallet("*") + await (metaMaskSnapWallet as any).init(windowObject) + return metaMaskSnapWallet as IStarknetWindowObject +} + function createMetaMaskProviderWrapper( walletInfo: WalletProvider, windowObject: Record, ): StarknetWindowObject { let metaMaskSnapWallet: IStarknetWindowObject | undefined - let isEnabling = false + let fetchPromise: Promise | undefined = undefined const metaMaskProviderWrapper: IStarknetWindowObject = { id: walletInfo.id, name: walletInfo.name, @@ -44,52 +69,13 @@ function createMetaMaskProviderWrapper( return metaMaskSnapWallet.request(call) }, async enable(): Promise { - if (isEnabling) { - // If enable is already being called, return a promise that waits for the current enable call to finish - return new Promise((resolve, reject) => { - const checkInterval = setInterval(() => { - if (!isEnabling) { - clearInterval(checkInterval) - if (metaMaskSnapWallet) { - resolve(metaMaskSnapWallet.enable()) - } else { - reject(new Error("Wallet not enabled")) - } - } - }, 100) - }) + if (!metaMaskSnapWallet) { + fetchPromise = fetchPromise || fetchMetaMaskSnapWallet(windowObject) + metaMaskSnapWallet = await fetchPromise } - isEnabling = true // Set the guard flag - try { - if (!metaMaskSnapWallet) { - await init({ - name: "MetaMaskStarknetSnapWallet", - remotes: [ - { - name: "MetaMaskStarknetSnapWallet", - alias: "MetaMaskStarknetSnapWallet", - entry: - "https://snaps.consensys.io/starknet/get-starknet/v1/remoteEntry.js", //"http://localhost:8082/remoteEntry.js", - }, - ], - }) - - const result = await loadRemote("MetaMaskStarknetSnapWallet/index") - - const { MetaMaskSnapWallet } = result as { - MetaMaskSnapWallet: any - MetaMaskSnap: any - } - metaMaskSnapWallet = new MetaMaskSnapWallet("*") - await (metaMaskSnapWallet as any).init(windowObject) - } - - const accounts = await metaMaskSnapWallet!.enable() - return accounts - } finally { - isEnabling = false // Reset the guard flag - } + const accounts = await metaMaskSnapWallet!.enable() + return accounts }, isPreauthorized() { return metaMaskSnapWallet?.isPreauthorized() ?? Promise.resolve(false) From 602219f65ee56819f1549e14238c82a4d444a5d8 Mon Sep 17 00:00:00 2001 From: Florin Dzeladini Date: Wed, 3 Jul 2024 12:41:40 +0200 Subject: [PATCH 12/12] fix: rollback provider detection back to metamaskBridge --- packages/core/src/wallet/metamaskBridge.ts | 91 ++++++++++++++++++++-- 1 file changed, 85 insertions(+), 6 deletions(-) diff --git a/packages/core/src/wallet/metamaskBridge.ts b/packages/core/src/wallet/metamaskBridge.ts index 63375d4..7f4bb7c 100644 --- a/packages/core/src/wallet/metamaskBridge.ts +++ b/packages/core/src/wallet/metamaskBridge.ts @@ -7,7 +7,82 @@ import type { import wallets, { WalletProvider } from "../discovery" import { init, loadRemote } from "@module-federation/runtime" -async function fetchMetaMaskSnapWallet(windowObject: Record) { +interface MetaMaskProvider { + isMetaMask: boolean + request(options: { method: string }): Promise +} + +function isMetaMaskProvider(obj: unknown): obj is MetaMaskProvider { + return ( + obj !== null && + typeof obj === "object" && + obj.hasOwnProperty("isMetaMask") && + obj.hasOwnProperty("request") + ) +} + +function detectMetaMaskProvider( + windowObject: Record, + { timeout = 3000 } = {}, +): Promise { + let handled = false + return new Promise((resolve) => { + const handleEIP6963Provider = (event: CustomEvent) => { + const { info, provider } = event.detail + if ( + ["io.metamask", "io.metamask.flask"].includes(info.rdns) && + isMetaMaskProvider(provider) + ) { + resolve(provider) + handled = true + } + } + + if (typeof windowObject.addEventListener === "function") { + windowObject.addEventListener( + "eip6963:announceProvider", + handleEIP6963Provider, + ) + } + + setTimeout(() => { + if (!handled) { + resolve(null) + } + }, timeout) + + // Notify event listeners and other parts of the dapp that a provider is requested. + if (typeof windowObject.dispatchEvent === "function") { + windowObject.dispatchEvent(new Event("eip6963:requestProvider")) + } + }) +} + +async function waitForMetaMaskProvider( + windowObject: Record, + { timeout = 3000, retries = 0 } = {}, +): Promise { + return detectMetaMaskProvider(windowObject, { timeout }) + .catch(function () { + return null + }) + .then(function (provider) { + if (provider || retries === 0) { + return provider + } + return waitForMetaMaskProvider(windowObject, { + timeout, + retries: retries - 1, + }) + }) +} + +async function detectMetamaskSupport(windowObject: Record) { + const provider = await waitForMetaMaskProvider(windowObject, { retries: 3 }) + return provider +} + +async function fetchMetaMaskSnapWallet(provider: unknown) { await init({ name: "MetaMaskStarknetSnapWallet", remotes: [ @@ -27,14 +102,13 @@ async function fetchMetaMaskSnapWallet(windowObject: Record) { MetaMaskSnap: any } - const metaMaskSnapWallet = new MetaMaskSnapWallet("*") - await (metaMaskSnapWallet as any).init(windowObject) + const metaMaskSnapWallet = new MetaMaskSnapWallet(provider, "*") return metaMaskSnapWallet as IStarknetWindowObject } function createMetaMaskProviderWrapper( walletInfo: WalletProvider, - windowObject: Record, + provider: unknown, ): StarknetWindowObject { let metaMaskSnapWallet: IStarknetWindowObject | undefined let fetchPromise: Promise | undefined = undefined @@ -70,7 +144,7 @@ function createMetaMaskProviderWrapper( }, async enable(): Promise { if (!metaMaskSnapWallet) { - fetchPromise = fetchPromise || fetchMetaMaskSnapWallet(windowObject) + fetchPromise = fetchPromise || fetchMetaMaskSnapWallet(provider) metaMaskSnapWallet = await fetchPromise } @@ -112,9 +186,14 @@ async function injectMetamaskBridge(windowObject: Record) { return } + const provider = await detectMetamaskSupport(windowObject) + if (!provider) { + return + } + windowObject.starknet_metamask = createMetaMaskProviderWrapper( metamaskWalletInfo, - windowObject, + provider, ) }