diff --git a/src/content-scripts/main.ts b/src/content-scripts/main.ts index e0dd90ae7..1daa909a6 100644 --- a/src/content-scripts/main.ts +++ b/src/content-scripts/main.ts @@ -4,10 +4,10 @@ import browser from 'webextension-polyfill'; import { APP_TITLE, ContentScriptType, - DISCONNECT_DAPP_EVENT, + DISCONNECT_DAPP_MSG_TYPE, PASS_TO_BG_EVENT, - RESPONSE_FROM_BG_EVENT, - SWITCH_CHAIN_EVENT, + RESPONSE_FROM_BG_MSG_TYPE, + SWITCH_CHAIN_MSG_TYPE, WEBSITES_ANALYTICS_ENABLED } from 'lib/constants'; import { serealizeError } from 'lib/intercom/helpers'; @@ -78,13 +78,13 @@ getIntercom().subscribe((msg?: TempleNotification) => { const { origins } = msg; if (origins.some(origin => window.origin === origin)) { - window.dispatchEvent(new CustomEvent(DISCONNECT_DAPP_EVENT)); + window.postMessage({ type: DISCONNECT_DAPP_MSG_TYPE }, window.origin); } break; case TempleMessageType.TempleEvmChainSwitched: const { origin, type, ...chainSwitchPayload } = msg; if (origin === window.origin) { - window.dispatchEvent(new CustomEvent(SWITCH_CHAIN_EVENT, { detail: chainSwitchPayload })); + window.postMessage({ type: SWITCH_CHAIN_MSG_TYPE, ...chainSwitchPayload }, window.origin); } } }); @@ -102,7 +102,7 @@ window.addEventListener(PASS_TO_BG_EVENT, evt => { }) .then((res: TempleResponse) => { if (res?.type === TempleMessageType.PageResponse && res.payload) { - window.dispatchEvent(new CustomEvent(RESPONSE_FROM_BG_EVENT, { detail: { ...res.payload, requestId } })); + window.postMessage({ type: RESPONSE_FROM_BG_MSG_TYPE, payload: res.payload, requestId }, window.origin); } }) .catch(err => console.error(err)); diff --git a/src/lib/constants.ts b/src/lib/constants.ts index 0cd3dc91c..22287ddb8 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -104,8 +104,8 @@ export const MAIN_CHAINS_IDS = [ export const PASS_TO_BG_EVENT = 'templePassToBackground'; -export const RESPONSE_FROM_BG_EVENT = 'templeResponseFromBackground'; +export const RESPONSE_FROM_BG_MSG_TYPE = 'templeResponseFromBackground'; -export const DISCONNECT_DAPP_EVENT = 'templeDisconnectDApp'; +export const DISCONNECT_DAPP_MSG_TYPE = 'templeDisconnectDApp'; -export const SWITCH_CHAIN_EVENT = 'templeSwitchChain'; +export const SWITCH_CHAIN_MSG_TYPE = 'templeSwitchChain'; diff --git a/src/temple/evm/web3-provider.ts b/src/temple/evm/web3-provider.ts index 9d0162b4b..1f096bfd7 100644 --- a/src/temple/evm/web3-provider.ts +++ b/src/temple/evm/web3-provider.ts @@ -10,7 +10,12 @@ import type { RpcSchemaOverride } from 'viem'; -import { DISCONNECT_DAPP_EVENT, PASS_TO_BG_EVENT, RESPONSE_FROM_BG_EVENT, SWITCH_CHAIN_EVENT } from 'lib/constants'; +import { + DISCONNECT_DAPP_MSG_TYPE, + PASS_TO_BG_EVENT, + RESPONSE_FROM_BG_MSG_TYPE, + SWITCH_CHAIN_MSG_TYPE +} from 'lib/constants'; import { ETHEREUM_MAINNET_CHAIN_ID } from 'lib/temple/types'; import { @@ -95,7 +100,6 @@ interface BackgroundErrorResponse { interface BackgroundSuccessResponse { data: BackgroundResponseData; - requestId: string; } type BackgroundResponse = BackgroundSuccessResponse | BackgroundErrorResponse; @@ -111,6 +115,29 @@ const identity = (x: T) => x; const noop = () => {}; const toHex = (value: number): HexString => `0x${value.toString(16)}`; +interface DisconnectDAppMessage { + type: typeof DISCONNECT_DAPP_MSG_TYPE; +} + +interface SwitchChainMessage { + type: typeof SWITCH_CHAIN_MSG_TYPE; + chainId: number; +} + +interface ResponseFromBgMessage { + type: typeof RESPONSE_FROM_BG_MSG_TYPE; + payload: any; + requestId: string; +} + +const isTypedMessage = (msg: any): msg is { type: string } => typeof msg === 'object' && msg && 'type' in msg; +const isDisconnectDAppMessage = (msg: any): msg is DisconnectDAppMessage => + isTypedMessage(msg) && msg.type === DISCONNECT_DAPP_MSG_TYPE; +const isSwitchChainMessage = (msg: any): msg is SwitchChainMessage => + isTypedMessage(msg) && msg.type === SWITCH_CHAIN_MSG_TYPE; +const isResponseFromBgMessage = (msg: any): msg is ResponseFromBgMessage => + isTypedMessage(msg) && msg.type === RESPONSE_FROM_BG_MSG_TYPE; + export class TempleWeb3Provider extends EventEmitter { private accounts: HexString[]; private chainId: HexString; @@ -136,12 +163,8 @@ export class TempleWeb3Provider extends EventEmitter { identity, undefined ).catch(error => console.error(error)); - window.addEventListener(DISCONNECT_DAPP_EVENT, this.handleDisconnect); - window.addEventListener(SWITCH_CHAIN_EVENT, e => { - const { chainId } = (e as CustomEvent<{ chainId: number }>).detail; - - this.updateChainId(toHex(chainId)); - }); + this.listenToTypedMessage(isDisconnectDAppMessage, this.handleDisconnect); + this.listenToTypedMessage(isSwitchChainMessage, ({ chainId }) => this.updateChainId(toHex(chainId))); } // @ts-expect-error @@ -304,32 +327,46 @@ export class TempleWeb3Provider extends EventEmitter { ); return new Promise>((resolve, reject) => { - const listener = (evt: Event) => { - const { requestId: reqIdFromEvent, ...responseContent } = (evt as CustomEvent>).detail; + const listener = (msg: ResponseFromBgMessage) => { + const reqIdFromEvent = msg.requestId; + const payload: BackgroundResponse = msg.payload; if (reqIdFromEvent !== requestId) { return; } - window.removeEventListener(RESPONSE_FROM_BG_EVENT, listener); + removeListener(); - if ('error' in responseContent) { - console.error('inpage got error from bg', responseContent); - reject(new ErrorWithCode(responseContent.error.code, responseContent.error.message)); + if ('error' in payload) { + console.error('inpage got error from bg', payload); + reject(new ErrorWithCode(payload.error.code, payload.error.message)); return; } - const { data } = responseContent; + const { data } = payload; effectFn(data); // @ts-expect-error resolve(toProviderResponse(data)); }; - window.addEventListener(RESPONSE_FROM_BG_EVENT, listener); + const removeListener = this.listenToTypedMessage(isResponseFromBgMessage, listener); }); } + private listenToTypedMessage(typeguard: (msg: any) => msg is T, callback: SyncFn) { + const listener = (evt: MessageEvent) => { + if (evt.origin === window.origin && typeguard(evt.data)) { + callback(evt.data); + } + }; + const removeListener = () => window.removeEventListener('message', listener); + + window.addEventListener('message', listener); + + return removeListener; + } + private getIconUrl = memoizee( // A page may not have a head element async (head: HTMLHeadElement | undefined) => {