diff --git a/packages/extension/package.json b/packages/extension/package.json index de5fa7b86..35c53b105 100644 --- a/packages/extension/package.json +++ b/packages/extension/package.json @@ -54,11 +54,11 @@ "ws": "^8.8.1" }, "scripts": { - "build": "NODE_ENV=production webpack", - "build:sourcemaps": "GEN_SOURCE_MAPS=true yarn build", + "build": "cross-env NODE_ENV=production webpack", + "build:sourcemaps": "cross-env GEN_SOURCE_MAPS=true yarn build", "start": "webpack", "dev": "concurrently -k -r \"webpack --color --watch\" \"yarn dev:hot-reload-server\"", - "dev:ui": "SHOW_DEV_UI=true yarn dev", + "dev:ui": "cross-env SHOW_DEV_UI=true yarn dev", "dev:hot-reload-server": "ts-node ./scripts/hot-reload-server.ts", "lint": "eslint . --cache --ext .ts,.tsx", "test": "vitest run", @@ -96,6 +96,7 @@ "bignumber.js": "^9.0.2", "buffer": "^6.0.3", "colord": "^2.9.2", + "cross-env": "^7.0.3", "dexie": "^3.2.2", "dexie-react-hooks": "^1.1.1", "ethers": "^5.5.1", diff --git a/packages/extension/src/background/index.ts b/packages/extension/src/background/index.ts index 0746e35e5..440c26df5 100644 --- a/packages/extension/src/background/index.ts +++ b/packages/extension/src/background/index.ts @@ -119,7 +119,7 @@ getAccounts() const safeMessages: MessageType["type"][] = [ "IS_PREAUTHORIZED", - "CONNECT_DAPP", + "ARGENT_CONNECT_DAPP", "DISCONNECT_ACCOUNT", "OPEN_UI", // answers @@ -151,9 +151,9 @@ const safeMessages: MessageType["type"][] = [ const safeIfPreauthorizedMessages: MessageType["type"][] = [ "EXECUTE_TRANSACTION", "SIGN_MESSAGE", - "REQUEST_TOKEN", - "REQUEST_ADD_CUSTOM_NETWORK", - "REQUEST_SWITCH_CUSTOM_NETWORK", + "ARGENT_REQUEST_TOKEN", + "ARGENT_REQUEST_ADD_CUSTOM_NETWORK", + "ARGENT_REQUEST_SWITCH_CUSTOM_NETWORK", "REQUEST_DECLARE_CONTRACT", ] @@ -181,7 +181,7 @@ const handleMessage = async ( actionQueue, } - const extensionUrl = browser.extension.getURL("") + const extensionUrl = browser.runtime.getURL("") const safeOrigin = extensionUrl.replace(/\/$/, "") const origin = getOriginFromSender(sender) const isSafeOrigin = Boolean(origin === safeOrigin) diff --git a/packages/extension/src/background/networkMessaging.ts b/packages/extension/src/background/networkMessaging.ts index 5f38ee3bb..c5efa0500 100644 --- a/packages/extension/src/background/networkMessaging.ts +++ b/packages/extension/src/background/networkMessaging.ts @@ -43,7 +43,7 @@ export const handleNetworkMessage: HandleMessage = async ({ }) } - case "REQUEST_ADD_CUSTOM_NETWORK": { + case "ARGENT_REQUEST_ADD_CUSTOM_NETWORK": { const exists = await getNetwork(msg.data.chainId) if (exists) { @@ -68,7 +68,7 @@ export const handleNetworkMessage: HandleMessage = async ({ }) } - case "REQUEST_SWITCH_CUSTOM_NETWORK": { + case "ARGENT_REQUEST_SWITCH_CUSTOM_NETWORK": { const { chainId } = msg.data const isHexChainId = number.isHex(chainId) diff --git a/packages/extension/src/background/preAuthorizationMessaging.ts b/packages/extension/src/background/preAuthorizationMessaging.ts index eb09adfc8..e0b6d899a 100644 --- a/packages/extension/src/background/preAuthorizationMessaging.ts +++ b/packages/extension/src/background/preAuthorizationMessaging.ts @@ -50,7 +50,7 @@ export const handlePreAuthorizationMessage: HandleMessage< } switch (msg.type) { - case "CONNECT_DAPP": { + case "ARGENT_CONNECT_DAPP": { const selectedAccount = await wallet.getSelectedAccount() if (!selectedAccount) { openUi() diff --git a/packages/extension/src/background/tokenMessaging.ts b/packages/extension/src/background/tokenMessaging.ts index 78306ef32..f451a3de5 100644 --- a/packages/extension/src/background/tokenMessaging.ts +++ b/packages/extension/src/background/tokenMessaging.ts @@ -9,7 +9,7 @@ export const handleTokenMessaging: HandleMessage = async ({ respond, }) => { switch (msg.type) { - case "REQUEST_TOKEN": { + case "ARGENT_REQUEST_TOKEN": { const selectedAccount = await wallet.getSelectedAccount() const exists = await hasToken({ networkId: diff --git a/packages/extension/src/background/wallet.ts b/packages/extension/src/background/wallet.ts index d25516712..152fe3752 100644 --- a/packages/extension/src/background/wallet.ts +++ b/packages/extension/src/background/wallet.ts @@ -73,7 +73,7 @@ const isDevOrTest = isDev || isTest const SCRYPT_N = isDevOrTest ? 64 : 262144 // 131072 is the default value used by ethers const CURRENT_BACKUP_VERSION = 1 -export const SESSION_DURATION = isDev ? 24 * 60 * 60 : 30 * 60 // 30 mins in prod, 24 hours in dev +export const SESSION_DURATION = isDev ? 24 * 60 : 30 // 30 mins in prod, 24 hours in dev. Note that the unit is minute, not second const CHECK_OFFSET = 10 diff --git a/packages/extension/src/inpage/index.ts b/packages/extension/src/inpage/index.ts index 161c87280..4adb353bb 100644 --- a/packages/extension/src/inpage/index.ts +++ b/packages/extension/src/inpage/index.ts @@ -1,3 +1,4 @@ +import type { StarknetWindowObject } from "@argent/x-window" import { assertNever } from "./../ui/services/assertNever" import type { WindowMessageType } from "../shared/messages" import { getProvider } from "../shared/network/provider" @@ -6,20 +7,24 @@ import { ArgentXAccount } from "./ArgentXAccount" import { sendMessage, waitForMessage } from "./messageActions" import { getIsPreauthorized } from "./messaging" import { starknetWindowObject, userEventHandlers } from "./starknetWindowObject" +import { isPlainObject } from "lodash-es" const INJECT_NAMES = ["starknet", "starknet_argentX"] function attach() { + window.starknetProviders = + window.starknetProviders && isPlainObject(window.starknetProviders) ? window.starknetProviders : {} + INJECT_NAMES.forEach((name) => { // we need 2 different try catch blocks because we want to execute both even if one of them fails try { - delete (window as any)[name] + delete (window.starknetProviders as any)[name] } catch (e) { // ignore } try { // set read only property to window - Object.defineProperty(window, name, { + Object.defineProperty(window.starknetProviders, name, { value: starknetWindowObject, writable: false, }) @@ -27,7 +32,8 @@ function attach() { // ignore } try { - ;(window as any)[name] = starknetWindowObject + ;(window.starknetProviders as any)[name] = starknetWindowObject + window.dispatchEvent(new Event(`starknet/${name}#initialized`)) // dApps could subscribe this event to detect whether the window object is available } catch { // ignore } @@ -36,13 +42,10 @@ function attach() { function attachHandler() { attach() - setTimeout(attach, 100) + // setTimeout(attach, 100) // no need to wait due to `initialized` event } // inject script attachHandler() -window.addEventListener("load", () => attachHandler()) -document.addEventListener("DOMContentLoaded", () => attachHandler()) -document.addEventListener("readystatechange", () => attachHandler()) window.addEventListener( "message", @@ -72,7 +75,7 @@ window.addEventListener( 10 * 60 * 1000, ) sendMessage({ - type: "CONNECT_DAPP", + type: "ARGENT_CONNECT_DAPP", }) const walletAccount = await walletAccountP @@ -118,3 +121,10 @@ window.addEventListener( } }, ) + +declare global { + interface Window { + // Inspired by EIP-5749: https://eips.ethereum.org/EIPS/eip-5749 + starknetProviders?: Record + } +} diff --git a/packages/extension/src/inpage/messageActions.ts b/packages/extension/src/inpage/messageActions.ts index d81922c96..9644eced5 100644 --- a/packages/extension/src/inpage/messageActions.ts +++ b/packages/extension/src/inpage/messageActions.ts @@ -5,7 +5,10 @@ const extensionId = document ?.getAttribute("data-extension-id") export function sendMessage(msg: MessageType): void { - return window.postMessage({ ...msg, extensionId }, window.location.origin) + // `bigint` can not be serialized by `window.postMessage` + const stringified = JSON.stringify(msg) + const parsed = JSON.parse(stringified) + return window.postMessage({ ...parsed, extensionId }, window.location.origin) } export function waitForMessage< diff --git a/packages/extension/src/inpage/requestMessageHandlers.ts b/packages/extension/src/inpage/requestMessageHandlers.ts index d2e3809de..1bb9e1cdd 100644 --- a/packages/extension/src/inpage/requestMessageHandlers.ts +++ b/packages/extension/src/inpage/requestMessageHandlers.ts @@ -10,7 +10,7 @@ export async function handleAddTokenRequest( callParams: WatchAssetParameters, ): Promise { sendMessage({ - type: "REQUEST_TOKEN", + type: "ARGENT_REQUEST_TOKEN", data: { address: callParams.options.address, symbol: callParams.options.symbol, @@ -59,7 +59,7 @@ export async function handleAddNetworkRequest( callParams: AddStarknetChainParameters, ): Promise { sendMessage({ - type: "REQUEST_ADD_CUSTOM_NETWORK", + type: "ARGENT_REQUEST_ADD_CUSTOM_NETWORK", data: { id: callParams.id, name: callParams.chainName, @@ -119,7 +119,7 @@ export async function handleSwitchNetworkRequest(callParams: { chainId: Network["chainId"] }): Promise { sendMessage({ - type: "REQUEST_SWITCH_CUSTOM_NETWORK", + type: "ARGENT_REQUEST_SWITCH_CUSTOM_NETWORK", data: { chainId: callParams.chainId }, }) diff --git a/packages/extension/src/inpage/starknetWindowObject.ts b/packages/extension/src/inpage/starknetWindowObject.ts index 9d350ac69..c19978df6 100644 --- a/packages/extension/src/inpage/starknetWindowObject.ts +++ b/packages/extension/src/inpage/starknetWindowObject.ts @@ -57,7 +57,7 @@ export const starknetWindowObject: StarknetWindowObject = { ), ]) sendMessage({ - type: "CONNECT_DAPP", + type: "ARGENT_CONNECT_DAPP", }) const walletAccount = await walletAccountP diff --git a/packages/extension/src/shared/messages/NetworkMessage.ts b/packages/extension/src/shared/messages/NetworkMessage.ts index 56ade20ac..86b7ec46f 100644 --- a/packages/extension/src/shared/messages/NetworkMessage.ts +++ b/packages/extension/src/shared/messages/NetworkMessage.ts @@ -20,7 +20,7 @@ export type NetworkMessage = } // - used by dapps to request addition of custom network - | { type: "REQUEST_ADD_CUSTOM_NETWORK"; data: Network } + | { type: "ARGENT_REQUEST_ADD_CUSTOM_NETWORK"; data: Network } | { type: "REQUEST_ADD_CUSTOM_NETWORK_RES"; data: { actionHash: string } } | { type: "REQUEST_ADD_CUSTOM_NETWORK_REJ" @@ -31,7 +31,7 @@ export type NetworkMessage = // - used by dapps to request switching of already added custom network | { - type: "REQUEST_SWITCH_CUSTOM_NETWORK" + type: "ARGENT_REQUEST_SWITCH_CUSTOM_NETWORK" data: { chainId: Network["chainId"] } } | { type: "REQUEST_SWITCH_CUSTOM_NETWORK_RES"; data: { actionHash: string } } diff --git a/packages/extension/src/shared/messages/PreAuthorisationMessage.ts b/packages/extension/src/shared/messages/PreAuthorisationMessage.ts index 3c54ace79..c1d3974a0 100644 --- a/packages/extension/src/shared/messages/PreAuthorisationMessage.ts +++ b/packages/extension/src/shared/messages/PreAuthorisationMessage.ts @@ -1,7 +1,7 @@ import { WalletAccount } from "../wallet.model" export type PreAuthorisationMessage = - | { type: "CONNECT_DAPP" } + | { type: "ARGENT_CONNECT_DAPP" } | { type: "CONNECT_DAPP_RES"; data: WalletAccount } | { type: "IS_PREAUTHORIZED" } | { type: "IS_PREAUTHORIZED_RES"; data: boolean } diff --git a/packages/extension/src/shared/messages/TokenMessage.ts b/packages/extension/src/shared/messages/TokenMessage.ts index 0f8879dd2..f4504ee87 100644 --- a/packages/extension/src/shared/messages/TokenMessage.ts +++ b/packages/extension/src/shared/messages/TokenMessage.ts @@ -2,7 +2,7 @@ import { RequestToken } from "../token/type" export type TokenMessage = // - used by dapps to request tokens - | { type: "REQUEST_TOKEN"; data: RequestToken } + | { type: "ARGENT_REQUEST_TOKEN"; data: RequestToken } | { type: "REQUEST_TOKEN_RES"; data: { actionHash?: string } } // returns no actionHash if the token already exists | { type: "REJECT_REQUEST_TOKEN"; data: { actionHash: string } } | { type: "APPROVE_REQUEST_TOKEN"; data: { actionHash: string } } diff --git a/packages/extension/src/shared/storage/array.ts b/packages/extension/src/shared/storage/array.ts index d25bbaa1c..517b6e08e 100644 --- a/packages/extension/src/shared/storage/array.ts +++ b/packages/extension/src/shared/storage/array.ts @@ -24,7 +24,7 @@ export function mergeArrayStableWith( compareFn: (a: T, b: T) => boolean = isEqual, insertMode: "unshift" | "push" = "push", ): T[] { - const result = reverse(uniqWith(reverse(source), compareFn)) // 2x reverse to keep the order while keeping the last occurence of duplicates + const result = reverse(uniqWith(reverse(source), compareFn)) // 2x reverse to keep the order while keeping the last occurrence of duplicates for (const element of other) { const index = result.findIndex((e) => compareFn(e, element)) if (index === -1) { diff --git a/yarn.lock b/yarn.lock index 25b46f8e6..bbf9134fc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9780,6 +9780,13 @@ create-require@^1.1.0: resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== +cross-env@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf" + integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw== + dependencies: + cross-spawn "^7.0.1" + cross-fetch@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f" @@ -9787,7 +9794,7 @@ cross-fetch@^3.1.5: dependencies: node-fetch "2.6.7" -cross-spawn@7.0.3, cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: +cross-spawn@7.0.3, cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==