Remove SingleSource compat layer (#808)

This commit is contained in:
Jaco
2021-09-05 11:10:04 +02:00
committed by GitHub
parent 50b066326f
commit 15ce1e17c6
4 changed files with 48 additions and 146 deletions
+2 -4
View File
@@ -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<boolean> {
return Promise.all([
singleSource(),
initMetaMaskSource()
initMetaMask()
]).then((): boolean => {
return true;
});
@@ -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<any>;
request: (args: RequestArguments) => Promise<unknown>;
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<InjectedAccount[]> => {
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<SignerResult> => {
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<boolean> {
return new Promise((resolve): void => {
const win = window as Window & Web3Window;
@@ -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<T> {
subscribe: (cb: (value: T) => void) => {
unsubscribe (): void;
};
}
interface SingleSourceAccount {
address: string;
assets: { assetId: number }[];
name: string;
}
interface SingleSource {
accounts$: Subscriber<SingleSourceAccount[]>;
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<Injected> => ({
accounts: {
// eslint-disable-next-line @typescript-eslint/require-await
get: async (): Promise<InjectedAccount[]> =>
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<boolean> {
return new Promise((resolve): void => {
const win = window as Window & SingleWindow;
if (win.SingleSource) {
injectSingleSource(win);
resolve(true);
} else {
resolve(false);
}
});
}
+26 -38
View File
@@ -73,35 +73,30 @@ export function web3Enable (originName: string): Promise<InjectedExtension[]> {
(): Promise<InjectedExtension[]> =>
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<void>): 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<void>): 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<InjectedExtension[]> {
return web3EnablePromise;
}
// retrieve all the accounts accross all providers
// retrieve all the accounts across all providers
export async function web3Accounts ({ accountType, ss58Format }: Web3AccountsOptions = {}): Promise<InjectedAccountWithMeta[]> {
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<InjectedAccountWithMeta[]> => {
try {
const list = await accounts.get();
injected.map(async ({ accounts, name: source }): Promise<InjectedAccountWithMeta[]> => {
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<void>,
{ ss58Format }: Web3AccountsOptions = {}
): Promise<Unsubcall> {
export async function web3AccountsSubscribe (cb: (accounts: InjectedAccountWithMeta[]) => void | Promise<void>, { ss58Format }: Web3AccountsOptions = {}): Promise<Unsubcall> {
if (!web3EnablePromise) {
return throwError('web3AccountsSubscribe');
}