@subwallet/extension-dapp 0.3.6-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +3 -0
  3. package/build/LICENSE +201 -0
  4. package/build/README.md +3 -0
  5. package/build/bundle-polkadot-extension-dapp.js +218 -0
  6. package/build/bundle.d.ts +13 -0
  7. package/build/bundle.js +222 -0
  8. package/build/cjs/bundle.js +297 -0
  9. package/build/cjs/detectOther.js +13 -0
  10. package/build/cjs/detectPackage.js +14 -0
  11. package/build/cjs/index.js +18 -0
  12. package/build/cjs/package.json +3 -0
  13. package/build/cjs/packageInfo.js +16 -0
  14. package/build/cjs/util.js +18 -0
  15. package/build/cjs/wrapBytes.js +23 -0
  16. package/build/detectOther.d.ts +7 -0
  17. package/build/detectOther.js +4 -0
  18. package/build/detectPackage.d.ts +1 -0
  19. package/build/detectPackage.js +7 -0
  20. package/build/index.d.ts +1 -0
  21. package/build/index.js +5 -0
  22. package/build/package.json +80 -0
  23. package/build/packageInfo.d.ts +6 -0
  24. package/build/packageInfo.js +9 -0
  25. package/build/util.d.ts +1 -0
  26. package/build/util.js +11 -0
  27. package/build/wrapBytes.d.ts +7 -0
  28. package/build/wrapBytes.js +9 -0
  29. package/build-cjs/bundle.js +297 -0
  30. package/build-cjs/detectOther.js +13 -0
  31. package/build-cjs/detectPackage.js +14 -0
  32. package/build-cjs/index.js +18 -0
  33. package/build-cjs/packageInfo.js +16 -0
  34. package/build-cjs/util.js +18 -0
  35. package/build-cjs/wrapBytes.js +23 -0
  36. package/package.json +33 -0
  37. package/src/bundle.ts +244 -0
  38. package/src/detectOther.ts +6 -0
  39. package/src/detectPackage.ts +11 -0
  40. package/src/index.ts +7 -0
  41. package/src/packageInfo.ts +6 -0
  42. package/src/util.ts +12 -0
  43. package/src/wrapBytes.spec.ts +135 -0
  44. package/src/wrapBytes.ts +12 -0
  45. package/tsconfig.build.json +12 -0
  46. package/tsconfig.build.tsbuildinfo +1 -0
  47. package/tsconfig.json +11 -0
package/src/bundle.ts ADDED
@@ -0,0 +1,244 @@
1
+ // Copyright 2019-2022 @subwallet/extension-dapp authors & contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import type { Injected, InjectedAccount, InjectedAccountWithMeta, InjectedExtension, InjectedExtensionInfo, InjectedProviderWithMeta, InjectedWindow, ProviderList, Unsubcall, Web3AccountsOptions } from '@subwallet/extension-inject/types';
5
+
6
+ import { u8aEq } from '@polkadot/util';
7
+ import { decodeAddress, encodeAddress } from '@polkadot/util-crypto';
8
+
9
+ import { documentReadyPromise } from './util';
10
+
11
+ // expose utility functions
12
+ export { packageInfo } from './packageInfo';
13
+ export { unwrapBytes, wrapBytes } from './wrapBytes';
14
+
15
+ // just a helper (otherwise we cast all-over, so shorter and more readable)
16
+ const win = window as Window & InjectedWindow;
17
+
18
+ // don't clobber the existing object, but ensure non-undefined
19
+ win.injectedWeb3 = win.injectedWeb3 || {};
20
+
21
+ // true when anything has been injected and is available
22
+ function web3IsInjected (): boolean {
23
+ return Object.keys(win.injectedWeb3).length !== 0;
24
+ }
25
+
26
+ // helper to throw a consistent error when not enabled
27
+ function throwError (method: string): never {
28
+ throw new Error(`${method}: web3Enable(originName) needs to be called before ${method}`);
29
+ }
30
+
31
+ // internal helper to map from Array<InjectedAccount> -> Array<InjectedAccountWithMeta>
32
+ function mapAccounts (source: string, list: InjectedAccount[], ss58Format?: number): InjectedAccountWithMeta[] {
33
+ return list.map(({ address, genesisHash, name, type }): InjectedAccountWithMeta => {
34
+ const encodedAddress = address.length === 42 ? address : encodeAddress(decodeAddress(address), ss58Format);
35
+
36
+ return ({
37
+ address: encodedAddress,
38
+ meta: { genesisHash, name, source },
39
+ type
40
+ });
41
+ });
42
+ }
43
+
44
+ // have we found a properly constructed window.injectedWeb3
45
+ let isWeb3Injected = web3IsInjected();
46
+
47
+ // we keep the last promise created around (for queries)
48
+ let web3EnablePromise: Promise<InjectedExtension[]> | null = null;
49
+
50
+ export { isWeb3Injected, web3EnablePromise };
51
+
52
+ function getWindowExtensions (originName: string): Promise<[InjectedExtensionInfo, Injected | void][]> {
53
+ return Promise.all(
54
+ Object.entries(win.injectedWeb3).map(
55
+ ([name, { enable, version }]): Promise<[InjectedExtensionInfo, Injected | void]> =>
56
+ Promise.all([
57
+ Promise.resolve({ name, version }),
58
+ enable(originName).catch((error: Error): void => {
59
+ console.error(`Error initializing ${name}: ${error.message}`);
60
+ })
61
+ ])
62
+ )
63
+ );
64
+ }
65
+
66
+ // enables all the providers found on the injected window interface
67
+ export function web3Enable (originName: string, compatInits: (() => Promise<boolean>)[] = []): Promise<InjectedExtension[]> {
68
+ if (!originName) {
69
+ throw new Error('You must pass a name for your app to the web3Enable function');
70
+ }
71
+
72
+ const initCompat = compatInits.length
73
+ ? Promise.all(compatInits.map((c) => c().catch(() => false)))
74
+ : Promise.resolve([true]);
75
+
76
+ web3EnablePromise = documentReadyPromise(
77
+ (): Promise<InjectedExtension[]> =>
78
+ initCompat.then(() =>
79
+ getWindowExtensions(originName)
80
+ .then((values): InjectedExtension[] =>
81
+ values
82
+ .filter((value): value is [InjectedExtensionInfo, Injected] => !!value[1])
83
+ .map(([info, ext]): InjectedExtension => {
84
+ // if we don't have an accounts subscriber, add a single-shot version
85
+ if (!ext.accounts.subscribe) {
86
+ ext.accounts.subscribe = (cb: (accounts: InjectedAccount[]) => void | Promise<void>): Unsubcall => {
87
+ ext.accounts.get().then(cb).catch(console.error);
88
+
89
+ return (): void => {
90
+ // no ubsubscribe needed, this is a single-shot
91
+ };
92
+ };
93
+ }
94
+
95
+ return { ...info, ...ext };
96
+ })
97
+ )
98
+ .catch((): InjectedExtension[] => [])
99
+ .then((values): InjectedExtension[] => {
100
+ const names = values.map(({ name, version }): string => `${name}/${version}`);
101
+
102
+ isWeb3Injected = web3IsInjected();
103
+ console.log(`web3Enable: Enabled ${values.length} extension${values.length !== 1 ? 's' : ''}: ${names.join(', ')}`);
104
+
105
+ return values;
106
+ })
107
+ )
108
+ );
109
+
110
+ return web3EnablePromise;
111
+ }
112
+
113
+ // retrieve all the accounts across all providers
114
+ export async function web3Accounts ({ accountType, ss58Format }: Web3AccountsOptions = {}): Promise<InjectedAccountWithMeta[]> {
115
+ if (!web3EnablePromise) {
116
+ return throwError('web3Accounts');
117
+ }
118
+
119
+ const accounts: InjectedAccountWithMeta[] = [];
120
+ const injected = await web3EnablePromise;
121
+
122
+ const retrieved = await Promise.all(
123
+ injected.map(async ({ accounts, name: source }): Promise<InjectedAccountWithMeta[]> => {
124
+ try {
125
+ const list = await accounts.get();
126
+
127
+ return mapAccounts(source, list.filter(({ type }) => type && accountType ? accountType.includes(type) : true), ss58Format);
128
+ } catch (error) {
129
+ // cannot handle this one
130
+ return [];
131
+ }
132
+ })
133
+ );
134
+
135
+ retrieved.forEach((result): void => {
136
+ accounts.push(...result);
137
+ });
138
+
139
+ const addresses = accounts.map(({ address }) => address);
140
+
141
+ console.log(`web3Accounts: Found ${accounts.length} address${accounts.length !== 1 ? 'es' : ''}: ${addresses.join(', ')}`);
142
+
143
+ return accounts;
144
+ }
145
+
146
+ export async function web3AccountsSubscribe (cb: (accounts: InjectedAccountWithMeta[]) => void | Promise<void>, { ss58Format }: Web3AccountsOptions = {}): Promise<Unsubcall> {
147
+ if (!web3EnablePromise) {
148
+ return throwError('web3AccountsSubscribe');
149
+ }
150
+
151
+ const accounts: Record<string, InjectedAccount[]> = {};
152
+
153
+ const triggerUpdate = (): void | Promise<void> =>
154
+ cb(
155
+ Object.entries(accounts).reduce(
156
+ (result: InjectedAccountWithMeta[], [source, list]): InjectedAccountWithMeta[] => {
157
+ result.push(...mapAccounts(source, list, ss58Format));
158
+
159
+ return result;
160
+ },
161
+ []
162
+ )
163
+ );
164
+
165
+ const unsubs = (await web3EnablePromise).map(
166
+ ({ accounts: { subscribe }, name: source }): Unsubcall =>
167
+ subscribe((result): void => {
168
+ accounts[source] = result;
169
+
170
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
171
+ triggerUpdate();
172
+ })
173
+ );
174
+
175
+ return (): void => {
176
+ unsubs.forEach((unsub): void => {
177
+ unsub();
178
+ });
179
+ };
180
+ }
181
+
182
+ // find a specific provider based on the name
183
+ export async function web3FromSource (source: string): Promise<InjectedExtension> {
184
+ if (!web3EnablePromise) {
185
+ return throwError('web3FromSource');
186
+ }
187
+
188
+ const sources = await web3EnablePromise;
189
+ const found = source && sources.find(({ name }): boolean => name === source);
190
+
191
+ if (!found) {
192
+ throw new Error(`web3FromSource: Unable to find an injected ${source}`);
193
+ }
194
+
195
+ return found;
196
+ }
197
+
198
+ // find a specific provider based on an address
199
+ export async function web3FromAddress (address: string): Promise<InjectedExtension> {
200
+ if (!web3EnablePromise) {
201
+ return throwError('web3FromAddress');
202
+ }
203
+
204
+ const accounts = await web3Accounts();
205
+ let found: InjectedAccountWithMeta | undefined;
206
+
207
+ if (address) {
208
+ const accountU8a = decodeAddress(address);
209
+
210
+ found = accounts.find((account): boolean => u8aEq(decodeAddress(account.address), accountU8a));
211
+ }
212
+
213
+ if (!found) {
214
+ throw new Error(`web3FromAddress: Unable to find injected ${address}`);
215
+ }
216
+
217
+ return web3FromSource(found.meta.source);
218
+ }
219
+
220
+ // retrieve all providers exposed by one source
221
+ export async function web3ListRpcProviders (source: string): Promise<ProviderList | null> {
222
+ const { provider } = await web3FromSource(source);
223
+
224
+ if (!provider) {
225
+ console.warn(`Extension ${source} does not expose any provider`);
226
+
227
+ return null;
228
+ }
229
+
230
+ return provider.listProviders();
231
+ }
232
+
233
+ // retrieve all providers exposed by one source
234
+ export async function web3UseRpcProvider (source: string, key: string): Promise<InjectedProviderWithMeta> {
235
+ const { provider } = await web3FromSource(source);
236
+
237
+ if (!provider) {
238
+ throw new Error(`Extension ${source} does not expose any provider`);
239
+ }
240
+
241
+ const meta = await provider.startProvider(key);
242
+
243
+ return { meta, provider };
244
+ }
@@ -0,0 +1,6 @@
1
+ // Copyright 2017-2022 @subwallet/extension-dapp authors & contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import { packageInfo as injectInfo } from '@subwallet/extension-inject/packageInfo';
5
+
6
+ export default [injectInfo];
@@ -0,0 +1,11 @@
1
+ // Copyright 2017-2022 @subwallet/extension-dapp authors & contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ // Do not edit, auto-generated by @polkadot/dev
5
+
6
+ import { detectPackage } from '@polkadot/util';
7
+
8
+ import others from './detectOther';
9
+ import { packageInfo } from './packageInfo';
10
+
11
+ detectPackage(packageInfo, null, others);
package/src/index.ts ADDED
@@ -0,0 +1,7 @@
1
+ // Copyright 2019-2022 @subwallet/extension-dapp authors & contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ // Since we inject into pages, we skip this
5
+ // import './detectPackage';
6
+
7
+ export * from './bundle';
@@ -0,0 +1,6 @@
1
+ // Copyright 2017-2022 @subwallet/extension-dapp authors & contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ // Do not edit, auto-generated by @polkadot/dev
5
+
6
+ export const packageInfo = { name: '@subwallet/extension-dapp', path: 'auto', type: 'auto', version: '0.3.6-0' };
package/src/util.ts ADDED
@@ -0,0 +1,12 @@
1
+ // Copyright 2019-2022 @subwallet/extension-dapp authors & contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ export function documentReadyPromise <T> (creator: () => Promise<T>): Promise<T> {
5
+ return new Promise((resolve): void => {
6
+ if (document.readyState === 'complete') {
7
+ resolve(creator());
8
+ } else {
9
+ window.addEventListener('load', () => resolve(creator()));
10
+ }
11
+ });
12
+ }
@@ -0,0 +1,135 @@
1
+ // Copyright 2019-2022 @subwallet/extension authors & contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import { u8aConcat, u8aEq, u8aToString } from '@polkadot/util';
5
+
6
+ import { ETHEREUM, POSTFIX, PREFIX, unwrapBytes, wrapBytes } from './wrapBytes';
7
+
8
+ const TEST_DATA = 'this is just some random message that we expect to be wrapped along the way';
9
+ const TEST_ETH = u8aConcat(ETHEREUM, TEST_DATA);
10
+ const TEST_WRAP_EMPTY = `${u8aToString(PREFIX)}${u8aToString(POSTFIX)}`;
11
+ const TEST_WRAP_FULL = `${u8aToString(PREFIX)}${TEST_DATA}${u8aToString(POSTFIX)}`;
12
+ const TEST_WARP_HALF_PRE = `${u8aToString(PREFIX)}${TEST_DATA}`;
13
+ const TEST_WRAP_HALF_POST = `${TEST_DATA}${u8aToString(POSTFIX)}`;
14
+
15
+ describe('wrapBytes', (): void => {
16
+ it('wraps empty bytes', (): void => {
17
+ expect(
18
+ u8aEq(
19
+ wrapBytes(new Uint8Array()),
20
+ u8aConcat(PREFIX, POSTFIX)
21
+ )
22
+ ).toBe(true);
23
+ });
24
+
25
+ it('wraps when no wrapping is detected', (): void => {
26
+ expect(
27
+ u8aToString(
28
+ wrapBytes(TEST_DATA)
29
+ )
30
+ ).toEqual(TEST_WRAP_FULL);
31
+ });
32
+
33
+ it('wraps when only start wrap is detected', (): void => {
34
+ expect(
35
+ u8aToString(
36
+ wrapBytes(TEST_WARP_HALF_PRE)
37
+ )
38
+ ).toEqual(`${u8aToString(PREFIX)}${TEST_WARP_HALF_PRE}${u8aToString(POSTFIX)}`);
39
+ });
40
+
41
+ it('wraps when only end wrap is detected', (): void => {
42
+ expect(
43
+ u8aToString(
44
+ wrapBytes(TEST_WRAP_HALF_POST)
45
+ )
46
+ ).toEqual(`${u8aToString(PREFIX)}${TEST_WRAP_HALF_POST}${u8aToString(POSTFIX)}`);
47
+ });
48
+
49
+ it('does not re-wrap when a wrap is already present', (): void => {
50
+ expect(
51
+ u8aToString(
52
+ wrapBytes(TEST_WRAP_FULL)
53
+ )
54
+ ).toEqual(TEST_WRAP_FULL);
55
+ });
56
+
57
+ it('does not re-wrap when a wrap (empty data) is already present', (): void => {
58
+ expect(
59
+ u8aToString(
60
+ wrapBytes(TEST_WRAP_EMPTY)
61
+ )
62
+ ).toEqual(TEST_WRAP_EMPTY);
63
+ });
64
+ });
65
+
66
+ describe('unwrapBytes', (): void => {
67
+ it('unwraps empty bytes', (): void => {
68
+ expect(
69
+ u8aEq(
70
+ unwrapBytes(new Uint8Array()),
71
+ new Uint8Array()
72
+ )
73
+ ).toBe(true);
74
+ });
75
+
76
+ it('unwraps when no wrapping is detected', (): void => {
77
+ expect(
78
+ u8aToString(
79
+ unwrapBytes(TEST_DATA)
80
+ )
81
+ ).toEqual(TEST_DATA);
82
+ });
83
+
84
+ it('unwraps when no wrapping is detected (only start)', (): void => {
85
+ expect(
86
+ u8aToString(
87
+ unwrapBytes(TEST_WARP_HALF_PRE)
88
+ )
89
+ ).toEqual(TEST_WARP_HALF_PRE);
90
+ });
91
+
92
+ it('unwraps when no wrapping is detected (only end)', (): void => {
93
+ expect(
94
+ u8aToString(
95
+ unwrapBytes(TEST_WRAP_HALF_POST)
96
+ )
97
+ ).toEqual(TEST_WRAP_HALF_POST);
98
+ });
99
+
100
+ it('unwraps when a wrap is present', (): void => {
101
+ expect(
102
+ u8aToString(
103
+ unwrapBytes(TEST_WRAP_FULL)
104
+ )
105
+ ).toEqual(TEST_DATA);
106
+ });
107
+
108
+ it('unwraps when a an empty wrap is present', (): void => {
109
+ expect(
110
+ u8aToString(
111
+ unwrapBytes(TEST_WRAP_EMPTY)
112
+ )
113
+ ).toEqual('');
114
+ });
115
+
116
+ describe('Ethereum-style', (): void => {
117
+ it('does not wrap an Ethereum wrap', (): void => {
118
+ expect(
119
+ u8aEq(
120
+ wrapBytes(TEST_ETH),
121
+ TEST_ETH
122
+ )
123
+ ).toBe(true);
124
+ });
125
+
126
+ it('does not unwrap an Ethereum wrap', (): void => {
127
+ expect(
128
+ u8aEq(
129
+ unwrapBytes(TEST_ETH),
130
+ TEST_ETH
131
+ )
132
+ ).toBe(true);
133
+ });
134
+ });
135
+ });
@@ -0,0 +1,12 @@
1
+ // Copyright 2019-2022 @subwallet/extension authors & contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import { U8A_WRAP_ETHEREUM, U8A_WRAP_POSTFIX, U8A_WRAP_PREFIX, u8aIsWrapped, u8aUnwrapBytes, u8aWrapBytes } from '@polkadot/util';
5
+
6
+ export const ETHEREUM = U8A_WRAP_ETHEREUM;
7
+ export const POSTFIX = U8A_WRAP_POSTFIX;
8
+ export const PREFIX = U8A_WRAP_PREFIX;
9
+
10
+ export const isWrapped = u8aIsWrapped;
11
+ export const unwrapBytes = u8aUnwrapBytes;
12
+ export const wrapBytes = u8aWrapBytes;
@@ -0,0 +1,12 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "baseUrl": "..",
5
+ "outDir": "./build",
6
+ "rootDir": "./src"
7
+ },
8
+ "references": [
9
+ { "path": "../extension-inject/tsconfig.build.json"
10
+ }
11
+ ]
12
+ }