diff --git a/packages/extension-dapp/src/compat/index.ts b/packages/extension-dapp/src/compat/index.ts index dcfe3a09..c8c26fda 100644 --- a/packages/extension-dapp/src/compat/index.ts +++ b/packages/extension-dapp/src/compat/index.ts @@ -1,14 +1,12 @@ // Copyright 2019-2021 @polkadot/extension-dapp authors & contributors // SPDX-License-Identifier: Apache-2.0 -import initMetaMaskSource from './metaMaskSource'; -import singleSource from './singleSource'; +import initMetaMask from './metamask'; // initialize all the compatibility engines export default function initCompat (): Promise { return Promise.all([ - singleSource(), - initMetaMaskSource() + initMetaMask() ]).then((): boolean => { return true; }); diff --git a/packages/extension-dapp/src/compat/metaMaskSource.ts b/packages/extension-dapp/src/compat/metamask.ts similarity index 66% rename from packages/extension-dapp/src/compat/metaMaskSource.ts rename to packages/extension-dapp/src/compat/metamask.ts index 88412b0f..0af40d40 100644 --- a/packages/extension-dapp/src/compat/metaMaskSource.ts +++ b/packages/extension-dapp/src/compat/metamask.ts @@ -7,6 +7,7 @@ import detectEthereumProvider from '@metamask/detect-provider'; import Web3 from 'web3'; import { SignerPayloadRaw, SignerResult } from '@polkadot/types/types'; +import { assert } from '@polkadot/util'; interface RequestArguments { method: string; @@ -18,29 +19,29 @@ interface EthRpcSubscription { } interface EthereumProvider { - request: (args: RequestArguments) => Promise; + request: (args: RequestArguments) => Promise; isMetaMask: boolean; - on: (name: string, cb: any) => EthRpcSubscription; + on: (name: string, cb: (value: unknown) => void) => EthRpcSubscription; } interface Web3Window extends InjectedWindow { // this is injected by metaMask - ethereum: any; + ethereum: unknown; } function isMetaMaskProvider (prov: unknown): EthereumProvider { - if (prov !== null) { - return (prov as EthereumProvider); - } else { - throw new Error('Injected provider is not MetaMask'); - } + assert(prov && (prov as EthereumProvider).isMetaMask, 'Injected provider is not MetaMask'); + + return (prov as EthereumProvider); } -// transfor the Web3 accounts into a simple address/name array +// transform the Web3 accounts into a simple address/name array function transformAccounts (accounts: string[]): InjectedAccount[] { - return accounts.map((acc, i) => { - return { address: acc, name: 'MetaMask Address #' + i.toString(), type: 'ethereum' }; - }); + return accounts.map((address, i) => ({ + address, + name: `MetaMask Address #${i}`, + type: 'ethereum' + })); } // add a compat interface of metaMaskSource to window.injectedWeb3 @@ -56,11 +57,13 @@ function injectMetaMaskWeb3 (win: Web3Window): void { return { accounts: { get: async (): Promise => { - return transformAccounts(await provider.request({ method: 'eth_requestAccounts' })); + const response = await provider.request({ method: 'eth_requestAccounts' }); + + return transformAccounts(response as string[]); }, subscribe: (cb: (accounts: InjectedAccount[]) => void): (() => void) => { - const sub = provider.on('accountsChanged', function (accounts: string[]) { - cb(transformAccounts(accounts)); + const sub = provider.on('accountsChanged', (accounts): void => { + cb(transformAccounts(accounts as string[])); }); // TODO: add onchainchanged @@ -71,9 +74,9 @@ function injectMetaMaskWeb3 (win: Web3Window): void { }, signer: { signRaw: async (raw: SignerPayloadRaw): Promise => { - const signature = (await provider.request({ method: 'eth_sign', params: [raw.address, Web3.utils.sha3(raw.data)] }) as string); + const signature = await provider.request({ method: 'eth_sign', params: [raw.address, Web3.utils.sha3(raw.data)] }); - return { id: 0, signature }; + return { id: 0, signature: signature as string }; } } }; @@ -82,8 +85,6 @@ function injectMetaMaskWeb3 (win: Web3Window): void { }; } -// returns the MetaMask source instance, as per -// https://github.com/cennznet/singlesource-extension/blob/f7cb35b54e820bf46339f6b88ffede1b8e140de0/react-example/src/App.js#L19 export default function initMetaMaskSource (): Promise { return new Promise((resolve): void => { const win = window as Window & Web3Window; diff --git a/packages/extension-dapp/src/compat/singleSource.ts b/packages/extension-dapp/src/compat/singleSource.ts deleted file mode 100644 index c482da21..00000000 --- a/packages/extension-dapp/src/compat/singleSource.ts +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2019-2021 @polkadot/extension-dapp authors & contributors -// SPDX-License-Identifier: Apache-2.0 - -import type { Signer } from '@polkadot/api/types'; -import type { Injected, InjectedAccount, InjectedWindow } from '@polkadot/extension-inject/types'; - -// RxJs interface, only the bare-bones of what we need here -interface Subscriber { - subscribe: (cb: (value: T) => void) => { - unsubscribe (): void; - }; -} - -interface SingleSourceAccount { - address: string; - assets: { assetId: number }[]; - name: string; -} - -interface SingleSource { - accounts$: Subscriber; - environment$: string[]; - signer: Signer; -} - -interface SingleWindow extends InjectedWindow { - SingleSource: SingleSource; -} - -// transform the SingleSource accounts into a simple address/name array -function transformAccounts (accounts: SingleSourceAccount[]): InjectedAccount[] { - return accounts.map(({ address, name }): InjectedAccount => ({ - address, - name - })); -} - -// add a compat interface of SingleSource to window.injectedWeb3 -function injectSingleSource (win: SingleWindow): void { - let accounts: InjectedAccount[] = []; - - // we don't yet have an accounts subscribe on the interface, simply get the - // accounts and store them, any get will resolve the last found values - win.SingleSource.accounts$.subscribe((_accounts): void => { - accounts = transformAccounts(_accounts); - }); - - // decorate the compat interface - win.injectedWeb3.SingleSource = { - // eslint-disable-next-line @typescript-eslint/no-unused-vars,@typescript-eslint/require-await - enable: async (origin: string): Promise => ({ - accounts: { - // eslint-disable-next-line @typescript-eslint/require-await - get: async (): Promise => - accounts, - subscribe: (cb: (accounts: InjectedAccount[]) => void): () => void => { - const sub = win.SingleSource.accounts$.subscribe((accounts): void => { - cb(transformAccounts(accounts)); - }); - - return (): void => { - sub.unsubscribe(); - }; - } - }, - signer: win.SingleSource.signer - }), - version: '0.0.0' - }; -} - -// returns the SingleSource instance, as per -// https://github.com/cennznet/singlesource-extension/blob/f7cb35b54e820bf46339f6b88ffede1b8e140de0/react-example/src/App.js#L19 -export default function initSingleSource (): Promise { - return new Promise((resolve): void => { - const win = window as Window & SingleWindow; - - if (win.SingleSource) { - injectSingleSource(win); - resolve(true); - } else { - resolve(false); - } - }); -} diff --git a/packages/extension-dapp/src/index.ts b/packages/extension-dapp/src/index.ts index 55242ea6..5beccf7c 100644 --- a/packages/extension-dapp/src/index.ts +++ b/packages/extension-dapp/src/index.ts @@ -73,35 +73,30 @@ export function web3Enable (originName: string): Promise { (): Promise => initCompat().then(() => getWindowExtensions(originName) - .then((values): InjectedExtension[] => { - return values + .then((values): InjectedExtension[] => + values .filter((value): value is [InjectedExtensionInfo, Injected] => !!value[1]) - .map( - ([info, ext]): InjectedExtension => { - // if we don't have an accounts subscriber, add a single-shot version - if (!ext.accounts.subscribe) { - ext.accounts.subscribe = (cb: (accounts: InjectedAccount[]) => void | Promise): Unsubcall => { - ext.accounts.get().then(cb).catch(console.error); + .map(([info, ext]): InjectedExtension => { + // if we don't have an accounts subscriber, add a single-shot version + if (!ext.accounts.subscribe) { + ext.accounts.subscribe = (cb: (accounts: InjectedAccount[]) => void | Promise): Unsubcall => { + ext.accounts.get().then(cb).catch(console.error); - return (): void => { - // no ubsubscribe needed, this is a single-shot - }; + return (): void => { + // no ubsubscribe needed, this is a single-shot }; - } - - return { ...info, ...ext }; + }; } - ); - } + + return { ...info, ...ext }; + }) ) .catch((): InjectedExtension[] => []) .then((values): InjectedExtension[] => { const names = values.map(({ name, version }): string => `${name}/${version}`); isWeb3Injected = web3IsInjected(); - console.log( - `web3Enable: Enabled ${values.length} extension${values.length !== 1 ? 's' : ''}: ${names.join(', ')}` - ); + console.log(`web3Enable: Enabled ${values.length} extension${values.length !== 1 ? 's' : ''}: ${names.join(', ')}`); return values; }) @@ -111,7 +106,7 @@ export function web3Enable (originName: string): Promise { return web3EnablePromise; } -// retrieve all the accounts accross all providers +// retrieve all the accounts across all providers export async function web3Accounts ({ accountType, ss58Format }: Web3AccountsOptions = {}): Promise { if (!web3EnablePromise) { return throwError('web3Accounts'); @@ -121,37 +116,30 @@ export async function web3Accounts ({ accountType, ss58Format }: Web3AccountsOpt const injected = await web3EnablePromise; const retrieved = await Promise.all( - injected.map( - async ({ accounts, name: source }): Promise => { - try { - const list = await accounts.get(); + injected.map(async ({ accounts, name: source }): Promise => { + try { + const list = await accounts.get(); - return mapAccounts(source, list.filter((acc) => acc.type && accountType ? accountType.includes(acc.type) : true), ss58Format); - } catch (error) { - // cannot handle this one - return []; - } + return mapAccounts(source, list.filter(({ type }) => type && accountType ? accountType.includes(type) : true), ss58Format); + } catch (error) { + // cannot handle this one + return []; } - ) + }) ); retrieved.forEach((result): void => { accounts.push(...result); }); - const addresses = accounts.map(({ address }): string => address); + const addresses = accounts.map(({ address }) => address); - console.log( - `web3Accounts: Found ${accounts.length} address${accounts.length !== 1 ? 'es' : ''}: ${addresses.join(', ')}` - ); + console.log(`web3Accounts: Found ${accounts.length} address${accounts.length !== 1 ? 'es' : ''}: ${addresses.join(', ')}`); return accounts; } -export async function web3AccountsSubscribe ( - cb: (accounts: InjectedAccountWithMeta[]) => void | Promise, - { ss58Format }: Web3AccountsOptions = {} -): Promise { +export async function web3AccountsSubscribe (cb: (accounts: InjectedAccountWithMeta[]) => void | Promise, { ss58Format }: Web3AccountsOptions = {}): Promise { if (!web3EnablePromise) { return throwError('web3AccountsSubscribe'); }