dequanto 0.1.39 → 0.1.45
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.
- package/lib/cjs/clients/ClientPool.js +23 -2
- package/lib/cjs/clients/ClientPool.js.map +1 -1
- package/lib/cjs/clients/WalletClient.js +98 -0
- package/lib/cjs/clients/WalletClient.js.map +1 -0
- package/lib/cjs/clients/Web3Client.js +39 -10
- package/lib/cjs/clients/Web3Client.js.map +1 -1
- package/lib/cjs/clients/Web3ClientFactory.js +7 -37
- package/lib/cjs/clients/Web3ClientFactory.js.map +1 -1
- package/lib/cjs/config/Config.js +4 -1
- package/lib/cjs/config/Config.js.map +1 -1
- package/lib/cjs/config/ConfigDefaults.js +3 -6
- package/lib/cjs/config/ConfigDefaults.js.map +1 -1
- package/lib/cjs/config/ConfigProvider.js +5 -1
- package/lib/cjs/config/ConfigProvider.js.map +1 -1
- package/lib/cjs/contracts/ContractWriter.js.map +1 -1
- package/lib/cjs/contracts/deploy/storage/DeploymentsStorage.js +10 -1
- package/lib/cjs/contracts/deploy/storage/DeploymentsStorage.js.map +1 -1
- package/lib/cjs/explorer/BlockchainExplorer.js +65 -43
- package/lib/cjs/explorer/BlockchainExplorer.js.map +1 -1
- package/lib/cjs/explorer/BlockchainExplorerFactory.js +6 -4
- package/lib/cjs/explorer/BlockchainExplorerFactory.js.map +1 -1
- package/lib/cjs/explorer/verifiers/FsHtmlVerifier.js +5 -5
- package/lib/cjs/explorer/verifiers/FsHtmlVerifier.js.map +1 -1
- package/lib/cjs/json/JsonArrayMultiStore.js.map +1 -1
- package/lib/cjs/json/JsonArrayStore.js +1 -1
- package/lib/cjs/json/JsonArrayStore.js.map +1 -1
- package/lib/cjs/json/JsonObjectStore.js +2 -1
- package/lib/cjs/json/JsonObjectStore.js.map +1 -1
- package/lib/cjs/json/JsonStoreFs.js +84 -18
- package/lib/cjs/json/JsonStoreFs.js.map +1 -1
- package/lib/cjs/models/TChain.js +4 -0
- package/lib/cjs/models/TChain.js.map +1 -0
- package/lib/cjs/models/TExplorer.js +4 -0
- package/lib/cjs/models/TExplorer.js.map +1 -0
- package/lib/cjs/models/TPlatform.js +1 -0
- package/lib/cjs/models/TPlatform.js.map +1 -1
- package/lib/cjs/rpc/transports/ITransport.js.map +1 -1
- package/lib/cjs/rpc/transports/RpcTransport.js +4 -0
- package/lib/cjs/rpc/transports/RpcTransport.js.map +1 -1
- package/lib/cjs/rpc/transports/compatibility/EIP1193Transport.js +14 -2
- package/lib/cjs/rpc/transports/compatibility/EIP1193Transport.js.map +1 -1
- package/lib/cjs/rpc/transports/compatibility/IEIP6963Provider.js +4 -0
- package/lib/cjs/rpc/transports/compatibility/IEIP6963Provider.js.map +1 -0
- package/lib/cjs/safe/GnosisSafeHandler.js.map +1 -1
- package/lib/cjs/tokens/TokenProviders/TPChain.js +5 -1
- package/lib/cjs/tokens/TokenProviders/TPChain.js.map +1 -1
- package/lib/cjs/txs/TxWriter.js +8 -1
- package/lib/cjs/txs/TxWriter.js.map +1 -1
- package/lib/cjs/utils/$buffer.js.map +1 -1
- package/lib/cjs/utils/$config.js +67 -2
- package/lib/cjs/utils/$config.js.map +1 -1
- package/lib/cjs/utils/$dependency.js +4 -0
- package/lib/cjs/utils/$dependency.js.map +1 -1
- package/lib/cjs/utils/$path.js +9 -0
- package/lib/cjs/utils/$path.js.map +1 -1
- package/lib/cjs/utils/$ref.js +30 -0
- package/lib/cjs/utils/$ref.js.map +1 -0
- package/lib/cjs/utils/$secret.js +15 -2
- package/lib/cjs/utils/$secret.js.map +1 -1
- package/lib/cjs/utils/$sig.js +18 -9
- package/lib/cjs/utils/$sig.js.map +1 -1
- package/lib/cjs/wallets/EIP6963ProviderFactory.js +192 -0
- package/lib/cjs/wallets/EIP6963ProviderFactory.js.map +1 -0
- package/lib/cjs/wallets/Signer.js +30 -0
- package/lib/cjs/wallets/Signer.js.map +1 -0
- package/lib/esm/clients/ClientPool.js.map +1 -1
- package/lib/esm/clients/ClientPool.mjs +23 -2
- package/lib/esm/clients/WalletClient.js.map +1 -0
- package/lib/esm/clients/WalletClient.mjs +91 -0
- package/lib/esm/clients/Web3Client.js.map +1 -1
- package/lib/esm/clients/Web3Client.mjs +39 -10
- package/lib/esm/clients/Web3ClientFactory.js.map +1 -1
- package/lib/esm/clients/Web3ClientFactory.mjs +7 -37
- package/lib/esm/config/Config.js.map +1 -1
- package/lib/esm/config/Config.mjs +4 -1
- package/lib/esm/config/ConfigDefaults.js.map +1 -1
- package/lib/esm/config/ConfigDefaults.mjs +3 -6
- package/lib/esm/config/ConfigProvider.js.map +1 -1
- package/lib/esm/config/ConfigProvider.mjs +5 -1
- package/lib/esm/contracts/ContractWriter.js.map +1 -1
- package/lib/esm/contracts/deploy/storage/DeploymentsStorage.js.map +1 -1
- package/lib/esm/contracts/deploy/storage/DeploymentsStorage.mjs +10 -1
- package/lib/esm/explorer/BlockchainExplorer.js.map +1 -1
- package/lib/esm/explorer/BlockchainExplorer.mjs +65 -43
- package/lib/esm/explorer/BlockchainExplorerFactory.js.map +1 -1
- package/lib/esm/explorer/BlockchainExplorerFactory.mjs +6 -4
- package/lib/esm/explorer/verifiers/FsHtmlVerifier.js.map +1 -1
- package/lib/esm/explorer/verifiers/FsHtmlVerifier.mjs +5 -5
- package/lib/esm/json/JsonArrayMultiStore.js.map +1 -1
- package/lib/esm/json/JsonArrayStore.js.map +1 -1
- package/lib/esm/json/JsonArrayStore.mjs +1 -1
- package/lib/esm/json/JsonObjectStore.js.map +1 -1
- package/lib/esm/json/JsonObjectStore.mjs +2 -1
- package/lib/esm/json/JsonStoreFs.js.map +1 -1
- package/lib/esm/json/JsonStoreFs.mjs +84 -18
- package/lib/esm/models/TChain.js.map +1 -0
- package/lib/esm/models/TChain.mjs +3 -0
- package/lib/esm/models/TExplorer.js.map +1 -0
- package/lib/esm/models/TExplorer.mjs +3 -0
- package/lib/esm/models/TPlatform.js.map +1 -1
- package/lib/esm/models/TPlatform.mjs +1 -0
- package/lib/esm/rpc/transports/ITransport.js.map +1 -1
- package/lib/esm/rpc/transports/RpcTransport.js.map +1 -1
- package/lib/esm/rpc/transports/RpcTransport.mjs +4 -0
- package/lib/esm/rpc/transports/compatibility/EIP1193Transport.js.map +1 -1
- package/lib/esm/rpc/transports/compatibility/EIP1193Transport.mjs +14 -2
- package/lib/esm/rpc/transports/compatibility/IEIP6963Provider.js.map +1 -0
- package/lib/esm/rpc/transports/compatibility/IEIP6963Provider.mjs +3 -0
- package/lib/esm/safe/GnosisSafeHandler.js.map +1 -1
- package/lib/esm/tokens/TokenProviders/TPChain.js.map +1 -1
- package/lib/esm/tokens/TokenProviders/TPChain.mjs +5 -1
- package/lib/esm/txs/TxWriter.js.map +1 -1
- package/lib/esm/txs/TxWriter.mjs +8 -1
- package/lib/esm/utils/$buffer.js.map +1 -1
- package/lib/esm/utils/$config.js.map +1 -1
- package/lib/esm/utils/$config.mjs +64 -2
- package/lib/esm/utils/$dependency.js.map +1 -1
- package/lib/esm/utils/$dependency.mjs +4 -0
- package/lib/esm/utils/$path.js.map +1 -1
- package/lib/esm/utils/$path.mjs +9 -0
- package/lib/esm/utils/$ref.js.map +1 -0
- package/lib/esm/utils/$ref.mjs +27 -0
- package/lib/esm/utils/$secret.js.map +1 -1
- package/lib/esm/utils/$secret.mjs +15 -2
- package/lib/esm/utils/$sig.js.map +1 -1
- package/lib/esm/utils/$sig.mjs +18 -9
- package/lib/esm/wallets/EIP6963ProviderFactory.js.map +1 -0
- package/lib/esm/wallets/EIP6963ProviderFactory.mjs +185 -0
- package/lib/esm/wallets/Signer.js.map +1 -0
- package/lib/esm/wallets/Signer.mjs +26 -0
- package/lib/types/clients/ClientPool.d.ts +13 -5
- package/lib/types/clients/WalletClient.d.ts +28 -0
- package/lib/types/clients/Web3Client.d.ts +7 -4
- package/lib/types/clients/Web3ClientFactory.d.ts +1 -1
- package/lib/types/clients/interfaces/IWeb3Client.d.ts +2 -5
- package/lib/types/config/AConfigBase.d.ts +0 -7
- package/lib/types/config/interface/IConfigData.d.ts +5 -2
- package/lib/types/explorer/BlockchainExplorer.d.ts +7 -4
- package/lib/types/explorer/BlockchainExplorerFactory.d.ts +7 -3
- package/lib/types/explorer/verifiers/FsHtmlVerifier.d.ts +3 -3
- package/lib/types/json/JsonArrayMultiStore.d.ts +2 -2
- package/lib/types/json/JsonArrayStore.d.ts +4 -3
- package/lib/types/json/JsonObjectStore.d.ts +5 -3
- package/lib/types/json/JsonStoreFs.d.ts +3 -2
- package/lib/types/models/TAccount.d.ts +9 -0
- package/lib/types/models/TChain.d.ts +45 -0
- package/lib/types/models/TEth.d.ts +8 -0
- package/lib/types/models/TExplorer.d.ts +31 -0
- package/lib/types/rpc/transports/ITransport.d.ts +2 -1
- package/lib/types/rpc/transports/compatibility/EIP1193Transport.d.ts +5 -1
- package/lib/types/rpc/transports/compatibility/IEIP6963Provider.d.ts +21 -0
- package/lib/types/utils/$config.d.ts +5 -0
- package/lib/types/utils/$ref.d.ts +11 -0
- package/lib/types/utils/$secret.d.ts +1 -0
- package/lib/types/utils/$sig.d.ts +1 -0
- package/lib/types/wallets/EIP6963ProviderFactory.d.ts +47 -0
- package/lib/types/wallets/Signer.d.ts +15 -0
- package/package.json +1 -1
- package/src/clients/ClientPool.ts +49 -15
- package/src/clients/WalletClient.ts +115 -0
- package/src/clients/Web3Client.ts +47 -16
- package/src/clients/Web3ClientFactory.ts +8 -39
- package/src/clients/interfaces/IWeb3Client.ts +2 -7
- package/src/config/AConfigBase.ts +3 -11
- package/src/config/Config.ts +6 -1
- package/src/config/ConfigDefaults.ts +3 -6
- package/src/config/ConfigProvider.ts +5 -1
- package/src/config/interface/IConfigData.ts +9 -4
- package/src/contracts/ContractWriter.ts +1 -0
- package/src/contracts/deploy/storage/DeploymentsStorage.ts +13 -3
- package/src/explorer/BlockchainExplorer.ts +82 -51
- package/src/explorer/BlockchainExplorerFactory.ts +19 -6
- package/src/explorer/verifiers/FsHtmlVerifier.ts +8 -8
- package/src/json/JsonArrayMultiStore.ts +2 -2
- package/src/json/JsonArrayStore.ts +5 -2
- package/src/json/JsonObjectStore.ts +7 -4
- package/src/json/JsonStoreFs.ts +103 -18
- package/src/models/TAccount.ts +10 -2
- package/src/models/TChain.ts +56 -0
- package/src/models/TEth.ts +9 -3
- package/src/models/TExplorer.ts +35 -0
- package/src/models/TPlatform.ts +1 -0
- package/src/rpc/transports/ITransport.ts +2 -1
- package/src/rpc/transports/RpcTransport.ts +4 -0
- package/src/rpc/transports/compatibility/EIP1193Transport.ts +19 -6
- package/src/rpc/transports/compatibility/IEIP6963Provider.ts +22 -0
- package/src/safe/GnosisSafeHandler.ts +1 -1
- package/src/tokens/TokenProviders/TPChain.ts +5 -1
- package/src/txs/TxWriter.ts +8 -2
- package/src/utils/$buffer.ts +1 -1
- package/src/utils/$config.ts +73 -2
- package/src/utils/$dependency.ts +5 -0
- package/src/utils/$path.ts +9 -0
- package/src/utils/$ref.ts +40 -0
- package/src/utils/$secret.ts +16 -3
- package/src/utils/$sig.ts +19 -10
- package/src/wallets/EIP6963ProviderFactory.ts +252 -0
- package/src/wallets/Signer.ts +32 -0
- package/lib/cjs/wallets/WalletBsc.js +0 -19
- package/lib/cjs/wallets/WalletBsc.js.map +0 -1
- package/lib/esm/wallets/WalletBsc.js.map +0 -1
- package/lib/esm/wallets/WalletBsc.mjs +0 -12
- package/lib/types/wallets/WalletBsc.d.ts +0 -10
- package/src/wallets/WalletBsc.ts +0 -13
package/src/json/JsonStoreFs.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { $require } from '@dequanto/utils/$require';
|
|
|
3
3
|
import { File, FileSafe } from 'atma-io';
|
|
4
4
|
import { class_Dfr, type Constructor } from 'atma-utils';
|
|
5
5
|
import { JsonConvert } from 'class-json';
|
|
6
|
+
import { $ref } from '@dequanto/utils/$ref';
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
export class JsonStoreFs<T> {
|
|
@@ -15,7 +16,7 @@ export class JsonStoreFs<T> {
|
|
|
15
16
|
private busy = false;
|
|
16
17
|
private watcherFn: (path?: string) => any
|
|
17
18
|
private watching = false;
|
|
18
|
-
private
|
|
19
|
+
private transport: ITransport;
|
|
19
20
|
|
|
20
21
|
public lock = new class_Dfr;
|
|
21
22
|
|
|
@@ -26,15 +27,19 @@ export class JsonStoreFs<T> {
|
|
|
26
27
|
, public format?: boolean
|
|
27
28
|
, public $default?: T
|
|
28
29
|
, public serializeFn?: (x: T) => any
|
|
30
|
+
, public persistence: 'file' | 'localStorage' = 'file'
|
|
29
31
|
) {
|
|
30
32
|
this.lock.resolve();
|
|
31
33
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
switch (persistence) {
|
|
35
|
+
case 'localStorage':
|
|
36
|
+
this.transport = new LocalStorageTransport(this.path);
|
|
37
|
+
break;
|
|
38
|
+
case 'file':
|
|
39
|
+
default:
|
|
40
|
+
this.transport = new FileTransport(this.path);
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
38
43
|
}
|
|
39
44
|
|
|
40
45
|
public watch (cb: typeof this.watcherFn) {
|
|
@@ -42,14 +47,13 @@ export class JsonStoreFs<T> {
|
|
|
42
47
|
this.watcherFn = cb;
|
|
43
48
|
}
|
|
44
49
|
public unwatch () {
|
|
45
|
-
|
|
50
|
+
this.transport.unwatch(this.watcherFn);
|
|
46
51
|
this.watcherFn = null;
|
|
47
52
|
}
|
|
48
53
|
public cleanCache () {
|
|
49
54
|
this.data = null;
|
|
50
55
|
// Should we do this? clear pending promise
|
|
51
|
-
|
|
52
|
-
this.file.content = null;
|
|
56
|
+
this.transport.cleanCache();
|
|
53
57
|
|
|
54
58
|
memd.fn.clearMemoized(this.readInner);
|
|
55
59
|
File.clearCache(this.path);
|
|
@@ -89,21 +93,17 @@ export class JsonStoreFs<T> {
|
|
|
89
93
|
|
|
90
94
|
@memd.deco.memoize({ perInstance: true })
|
|
91
95
|
private async readInner () {
|
|
92
|
-
let exists = await
|
|
96
|
+
let exists = await this.transport.exists();
|
|
93
97
|
if (exists === false) {
|
|
94
98
|
return this.$default;
|
|
95
99
|
}
|
|
96
|
-
let str = await this.
|
|
97
|
-
skipHooks: true,
|
|
98
|
-
encoding: 'utf8',
|
|
99
|
-
cached: false
|
|
100
|
-
});
|
|
100
|
+
let str = await this.transport.readAsync();
|
|
101
101
|
if (str == null) {
|
|
102
102
|
return this.$default;
|
|
103
103
|
}
|
|
104
104
|
let data = this.decode(str);
|
|
105
105
|
if (this.watcherFn != null && this.watching === false) {
|
|
106
|
-
|
|
106
|
+
this.transport.watch(this.watcherFn);
|
|
107
107
|
this.watching = true;
|
|
108
108
|
}
|
|
109
109
|
return data;
|
|
@@ -113,7 +113,7 @@ export class JsonStoreFs<T> {
|
|
|
113
113
|
let v = this.version;
|
|
114
114
|
let str = this.encode(data);
|
|
115
115
|
try {
|
|
116
|
-
await this.
|
|
116
|
+
await this.transport.writeAsync(str);
|
|
117
117
|
this.lock.resolve();
|
|
118
118
|
this.callWriteListeners(v, null);
|
|
119
119
|
} catch (error) {
|
|
@@ -186,3 +186,88 @@ export class JsonStoreFs<T> {
|
|
|
186
186
|
return JSON.stringify(data, null, format ? ' ' : null)
|
|
187
187
|
}
|
|
188
188
|
}
|
|
189
|
+
|
|
190
|
+
interface ITransport {
|
|
191
|
+
writeAsync(str: string): Promise<void>
|
|
192
|
+
readAsync(): Promise<string>
|
|
193
|
+
|
|
194
|
+
watch (watcherFn: (path?: string) => any)
|
|
195
|
+
unwatch (watcherFn: (path?: string) => any)
|
|
196
|
+
|
|
197
|
+
cleanCache()
|
|
198
|
+
exists (): Promise<boolean>
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
class FileTransport implements ITransport {
|
|
202
|
+
private file: InstanceType<typeof File>;
|
|
203
|
+
|
|
204
|
+
constructor (public path: string) {
|
|
205
|
+
const FileCtor = FileSafe ?? File
|
|
206
|
+
this.file = new FileCtor(this.path, {
|
|
207
|
+
cached: false,
|
|
208
|
+
processSafe: true,
|
|
209
|
+
threadSafe: true,
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
async exists(): Promise<boolean> {
|
|
213
|
+
return File.existsAsync (this.path);
|
|
214
|
+
}
|
|
215
|
+
async writeAsync(str: string) {
|
|
216
|
+
await this.file.writeAsync(str, { skipHooks: true });
|
|
217
|
+
}
|
|
218
|
+
async readAsync(): Promise<string> {
|
|
219
|
+
let str = await this.file.readAsync <string> ({
|
|
220
|
+
skipHooks: true,
|
|
221
|
+
encoding: 'utf8',
|
|
222
|
+
cached: false
|
|
223
|
+
});
|
|
224
|
+
return str;
|
|
225
|
+
}
|
|
226
|
+
async watch (watcherFn: (path?: string) => any) {
|
|
227
|
+
File.watch(this.path, watcherFn);
|
|
228
|
+
}
|
|
229
|
+
async unwatch (watcherFn: (path?: string) => any) {
|
|
230
|
+
File.unwatch(this.path, watcherFn);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
async cleanCache () {
|
|
234
|
+
(this.file as any).pending = null;
|
|
235
|
+
this.file.content = null;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
class LocalStorageTransport implements ITransport {
|
|
242
|
+
private global = $ref.getGlobal();
|
|
243
|
+
private listener: (event) => void;
|
|
244
|
+
|
|
245
|
+
constructor (public path: string) {
|
|
246
|
+
$require.notNull(this.global.localStorage, `LocalStorage is not available`);
|
|
247
|
+
}
|
|
248
|
+
async writeAsync(str: string) {
|
|
249
|
+
this.global.localStorage.setItem(this.path, str);
|
|
250
|
+
}
|
|
251
|
+
async readAsync(): Promise<string> {
|
|
252
|
+
return this.global.localStorage.getItem(this.path);
|
|
253
|
+
}
|
|
254
|
+
async exists (): Promise<boolean> {
|
|
255
|
+
// To prevent double load with "getItem", assume the existence of the item, later in readAsync the NULL will be handled.
|
|
256
|
+
return true;
|
|
257
|
+
}
|
|
258
|
+
async watch (watcherFn: (path?: string) => any) {
|
|
259
|
+
this.listener ??= (event) => {
|
|
260
|
+
if (event.key === this.path) {
|
|
261
|
+
watcherFn(this.path);
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
this.global.addEventListener('storage', this.listener, false);
|
|
265
|
+
}
|
|
266
|
+
async unwatch (watcherFn: (path?: string) => any) {
|
|
267
|
+
this.global.removeEventListener('storage', this.listener, false);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
async cleanCache () {
|
|
271
|
+
// no cached
|
|
272
|
+
}
|
|
273
|
+
}
|
package/src/models/TAccount.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import type { RpcTypes } from '@dequanto/rpc/Rpc'
|
|
1
2
|
import { TAddress } from './TAddress';
|
|
2
3
|
import { TEth } from './TEth';
|
|
3
4
|
import { TPlatform } from './TPlatform';
|
|
4
5
|
|
|
5
|
-
|
|
6
6
|
export interface IAccount {
|
|
7
7
|
type?: 'eoa' | 'safe' | 'erc4337'
|
|
8
8
|
name?: string
|
|
@@ -19,7 +19,15 @@ export interface IAccountTx extends IAccount {
|
|
|
19
19
|
|
|
20
20
|
export interface EoAccount extends IAccount {
|
|
21
21
|
type?: 'eoa'
|
|
22
|
-
key?: TEth.Hex | `p1:0x${string}
|
|
22
|
+
key?: TEth.Hex | `p1:0x${string}`
|
|
23
|
+
signer?: IRpcSigner
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface IRpcSigner {
|
|
27
|
+
eth_sign (account: TEth.Address, data: TEth.Hex): Promise<TEth.Hex>
|
|
28
|
+
eth_signTransaction (tx: TEth.TxLike): Promise<TEth.Hex>
|
|
29
|
+
eth_signTypedData_v4 (address: TEth.Address, typedData: Partial<RpcTypes.TypedData>): Promise<TEth.Hex>
|
|
30
|
+
personal_sign (challenge: string, address: TEth.Address): Promise<TEth.Hex>
|
|
23
31
|
}
|
|
24
32
|
|
|
25
33
|
export interface SafeAccount extends IAccount {
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { IRpcConfig } from '@dequanto/clients/ClientPool'
|
|
2
|
+
import { TEth } from './TEth'
|
|
3
|
+
import { IToken } from './IToken'
|
|
4
|
+
import { TExplorer } from './TExplorer'
|
|
5
|
+
|
|
6
|
+
export interface TChain {
|
|
7
|
+
name?: string
|
|
8
|
+
icon?: string
|
|
9
|
+
wwww?: string
|
|
10
|
+
|
|
11
|
+
platform: TEth.Platform
|
|
12
|
+
aliases?: string[]
|
|
13
|
+
|
|
14
|
+
chainId?: number
|
|
15
|
+
chainToken?: string
|
|
16
|
+
|
|
17
|
+
endpoints: IRpcConfig[]
|
|
18
|
+
|
|
19
|
+
explorers: TExplorer[]
|
|
20
|
+
|
|
21
|
+
tokens?: IToken[]
|
|
22
|
+
|
|
23
|
+
defaultTxType?: 0 | 1 | 2;
|
|
24
|
+
defaultGasPriceRatio?: number;
|
|
25
|
+
|
|
26
|
+
// block time in ms
|
|
27
|
+
blockTimeAvg?: number;
|
|
28
|
+
|
|
29
|
+
erc4337?: {
|
|
30
|
+
name: string;
|
|
31
|
+
contracts: {
|
|
32
|
+
entryPoint: TEth.Address;
|
|
33
|
+
accountFactory: TEth.Address;
|
|
34
|
+
};
|
|
35
|
+
}[];
|
|
36
|
+
|
|
37
|
+
safe?: {
|
|
38
|
+
transactionService: `https://${string}`
|
|
39
|
+
contracts: {
|
|
40
|
+
Safe: TEth.Address;
|
|
41
|
+
SafeL2?: TEth.Address;
|
|
42
|
+
SafeProxyFactory: TEth.Address;
|
|
43
|
+
MultiSend: TEth.Address;
|
|
44
|
+
CreateCall?: TEth.Address;
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
flashbots?: {
|
|
48
|
+
url: string;
|
|
49
|
+
};
|
|
50
|
+
spotPriceAggregator?: {
|
|
51
|
+
aggregator: TEth.Address
|
|
52
|
+
};
|
|
53
|
+
ens?: {
|
|
54
|
+
registry: TEth.Address
|
|
55
|
+
}
|
|
56
|
+
}
|
package/src/models/TEth.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { RpcTypes } from '@dequanto/rpc/Rpc'
|
|
1
2
|
import { TPlatform } from './TPlatform'
|
|
2
3
|
|
|
3
4
|
export namespace TEth {
|
|
@@ -143,6 +144,14 @@ export namespace TEth {
|
|
|
143
144
|
export interface EoAccount extends IAccount {
|
|
144
145
|
type?: 'eoa'
|
|
145
146
|
key?: TEth.Hex | `p1:0x${string}`;
|
|
147
|
+
signer?: IRpcSigner
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export interface IRpcSigner {
|
|
151
|
+
eth_sign (account: TEth.Address, data: TEth.Hex): Promise<TEth.Hex>
|
|
152
|
+
eth_signTransaction (tx: TEth.TxLike): Promise<TEth.Hex>
|
|
153
|
+
eth_signTypedData_v4 (address: TEth.Address, typedData: Partial<RpcTypes.TypedData>): Promise<TEth.Hex>
|
|
154
|
+
personal_sign (challenge: string, address: TEth.Address): Promise<TEth.Hex>
|
|
146
155
|
}
|
|
147
156
|
|
|
148
157
|
export interface SafeAccount extends IAccount {
|
|
@@ -215,9 +224,6 @@ export namespace TEth {
|
|
|
215
224
|
internalType?: string;
|
|
216
225
|
}
|
|
217
226
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
227
|
}
|
|
222
228
|
|
|
223
229
|
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Web3Client } from '@dequanto/clients/Web3Client'
|
|
2
|
+
import { IContractDetails } from './IContractDetails'
|
|
3
|
+
import { TEth } from './TEth'
|
|
4
|
+
|
|
5
|
+
/** Blockchain explorer settings - in config */
|
|
6
|
+
export interface TExplorerDefinition {
|
|
7
|
+
platform: TEth.Platform
|
|
8
|
+
|
|
9
|
+
name?: string
|
|
10
|
+
standard?: 'EIP3091' | string
|
|
11
|
+
url?: string
|
|
12
|
+
|
|
13
|
+
key?: string
|
|
14
|
+
api?: string | { url?: string, key?: string }
|
|
15
|
+
|
|
16
|
+
verification?: boolean | 'fs'
|
|
17
|
+
|
|
18
|
+
ABI_CACHE?: string
|
|
19
|
+
CONTRACTS?: IContractDetails[]
|
|
20
|
+
|
|
21
|
+
getWeb3?: (platform?: TEth.Platform) => Web3Client
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Blockchain explorer settings - normalized */
|
|
25
|
+
export interface TExplorer {
|
|
26
|
+
platform: TEth.Platform
|
|
27
|
+
|
|
28
|
+
name: string
|
|
29
|
+
standard: 'EIP3091' | string
|
|
30
|
+
url: string
|
|
31
|
+
|
|
32
|
+
api: { url: string, key?: string }
|
|
33
|
+
|
|
34
|
+
verification: boolean | 'fs'
|
|
35
|
+
}
|
package/src/models/TPlatform.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// https://github.com/ethereum-lists/chains
|
|
2
2
|
// https://chainid.network/chains.json
|
|
3
3
|
// https://github.com/DefiLlama/chainlist/blob/main/constants/extraRpcs.js
|
|
4
|
+
// https://api.llama.fi/chains
|
|
4
5
|
|
|
5
6
|
// https://eips.ethereum.org/EIPS/eip-3770
|
|
6
7
|
export type TPlatform = 'eth'
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { IWeb3EndpointOptions } from '@dequanto/clients/interfaces/IWeb3EndpointOptions';
|
|
2
2
|
import type { TEth } from '@dequanto/models/TEth';
|
|
3
3
|
import type { ClientOptions } from 'ws'
|
|
4
|
+
import { IEip1193Provider } from './compatibility/EIP1193Transport';
|
|
4
5
|
|
|
5
6
|
export namespace TTransport {
|
|
6
7
|
|
|
@@ -39,7 +40,7 @@ export namespace TTransport {
|
|
|
39
40
|
|
|
40
41
|
export namespace Options {
|
|
41
42
|
|
|
42
|
-
export type Any = string | Http | Ws | Wrapped | Transport | Web3Wrapper;
|
|
43
|
+
export type Any = string | Http | Ws | Wrapped | Transport | Web3Wrapper | IEip1193Provider;
|
|
43
44
|
|
|
44
45
|
export type Http = {
|
|
45
46
|
url: string
|
|
@@ -51,7 +51,11 @@ export namespace RpcTransport {
|
|
|
51
51
|
if (isEIP1193Compatible(mix.web3)) {
|
|
52
52
|
return new EIP1193Transport(mix.web3);
|
|
53
53
|
}
|
|
54
|
+
if (isTransport(mix.web3)) {
|
|
55
|
+
return mix.web3;
|
|
56
|
+
}
|
|
54
57
|
}
|
|
58
|
+
console.error(mix);
|
|
55
59
|
throw new Error(`Unknown transport: ${JSON.stringify(mix)}`);
|
|
56
60
|
}
|
|
57
61
|
|
|
@@ -4,7 +4,11 @@ import { RpcSubscription } from '@dequanto/rpc/RpcSubscription';
|
|
|
4
4
|
import alot from 'alot';
|
|
5
5
|
|
|
6
6
|
export interface IEip1193Provider {
|
|
7
|
-
sendAsync
|
|
7
|
+
sendAsync? (request: Object, callback: Function): void;
|
|
8
|
+
request (args: {
|
|
9
|
+
method: string;
|
|
10
|
+
params?: any[];
|
|
11
|
+
}): Promise<unknown>;
|
|
8
12
|
}
|
|
9
13
|
|
|
10
14
|
|
|
@@ -22,9 +26,20 @@ export class EIP1193Transport implements TTransport.Transport {
|
|
|
22
26
|
return this.request(x);
|
|
23
27
|
}).toArrayAsync({ threads: 5 });
|
|
24
28
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
29
|
+
if (typeof this.provider.sendAsync === 'function') {
|
|
30
|
+
let result = await $promise.fromCallbackCtx(this.provider, this.provider.sendAsync, req);
|
|
31
|
+
return result;
|
|
32
|
+
}
|
|
33
|
+
if (typeof this.provider.request === 'function') {
|
|
34
|
+
let result = await this.provider.request(req);
|
|
35
|
+
// Normalize response to EIP-1193 format
|
|
36
|
+
return {
|
|
37
|
+
id: req.id,
|
|
38
|
+
jsonrpc: '2.0',
|
|
39
|
+
result
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
throw new Error(`Invalid transport with no sendAsync, request methods`);
|
|
28
43
|
}
|
|
29
44
|
|
|
30
45
|
async subscribe(req: TTransport.Request): Promise<TTransport.Subscription<any>> {
|
|
@@ -33,6 +48,4 @@ export class EIP1193Transport implements TTransport.Transport {
|
|
|
33
48
|
unsubscribe(req: TTransport.Request & { method: 'eth_unsubscribe'; params: [number]; }): Promise<RpcSubscription<any>> {
|
|
34
49
|
throw new Error('Method not implemented.');
|
|
35
50
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
51
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface IEIP6963Provider {
|
|
2
|
+
isStatus?: boolean;
|
|
3
|
+
|
|
4
|
+
request: (request: { method: string, params?: Array<any> }) => Promise<any>;
|
|
5
|
+
|
|
6
|
+
on(event: 'accountsChanged', handler: (accounts: Array<string>) => void)
|
|
7
|
+
on(event: 'chainChanged', handler: (chainId: string) => void)
|
|
8
|
+
on(event: 'connect', handler: (connectInfo: ConnectInfo) => void)
|
|
9
|
+
on(event: 'disconnect', handler: (error: ProviderRpcError) => void)
|
|
10
|
+
|
|
11
|
+
removeListener(event: 'accountsChanged' | 'chainChanged' | 'connect' | 'disconnect', handler: (...args) => void)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
interface ConnectInfo {
|
|
16
|
+
chainId: string;
|
|
17
|
+
}
|
|
18
|
+
interface ProviderRpcError extends Error {
|
|
19
|
+
message: string
|
|
20
|
+
code: number
|
|
21
|
+
data?: unknown
|
|
22
|
+
}
|
|
@@ -69,6 +69,7 @@ export class GnosisSafeHandler {
|
|
|
69
69
|
|
|
70
70
|
async submitTransaction(safeTxHash: string, options?: { threshold?: number }) {
|
|
71
71
|
let tx = await this.transport.getTx(safeTxHash);
|
|
72
|
+
|
|
72
73
|
let writer = di.resolve(ContractWriter, this.safeAddress, this.client);
|
|
73
74
|
let confirmations = tx.confirmations;
|
|
74
75
|
|
|
@@ -213,7 +214,6 @@ export class GnosisSafeHandler {
|
|
|
213
214
|
let {
|
|
214
215
|
signature,
|
|
215
216
|
} = await this.createTxSignature(safeTxHash, owner);
|
|
216
|
-
|
|
217
217
|
return {
|
|
218
218
|
address: owner.address.toLowerCase(),
|
|
219
219
|
signature: signature
|
|
@@ -4,6 +4,7 @@ import { TAddress } from '@dequanto/models/TAddress';
|
|
|
4
4
|
import { TPlatform } from '@dequanto/models/TPlatform';
|
|
5
5
|
import { ITokenProvider } from './ITokenProvider';
|
|
6
6
|
import { ContractReader } from '@dequanto/contracts/ContractReader';
|
|
7
|
+
import { Web3ClientFactory } from '@dequanto/clients/Web3ClientFactory';
|
|
7
8
|
|
|
8
9
|
export class TPChain implements ITokenProvider {
|
|
9
10
|
|
|
@@ -12,9 +13,12 @@ export class TPChain implements ITokenProvider {
|
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
async getByAddress(platform: TPlatform, address: TAddress) {
|
|
15
|
-
if (this.platform !== platform) {
|
|
16
|
+
if (this.platform !== platform || platform === 'hardhat') {
|
|
16
17
|
return null;
|
|
17
18
|
}
|
|
19
|
+
if (this.client == null) {
|
|
20
|
+
this.client = await Web3ClientFactory.getAsync(platform);
|
|
21
|
+
}
|
|
18
22
|
|
|
19
23
|
let reader = new ContractReader(this.client)
|
|
20
24
|
try {
|
package/src/txs/TxWriter.ts
CHANGED
|
@@ -173,8 +173,15 @@ export class TxWriter extends class_EventEmitter<ITxWriterEvents> {
|
|
|
173
173
|
|
|
174
174
|
let agent = TxWriterAccountAgents.get(this.account);
|
|
175
175
|
if (agent != null) {
|
|
176
|
+
|
|
176
177
|
let sender = await this.getSender();
|
|
177
|
-
let innerWriter
|
|
178
|
+
let innerWriter: TxWriter;
|
|
179
|
+
try {
|
|
180
|
+
innerWriter = await agent.process(sender, this.account, this);
|
|
181
|
+
} catch (error) {
|
|
182
|
+
this.onCompleted.reject(error);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
178
185
|
this.pipeInnerWriter(innerWriter);
|
|
179
186
|
return;
|
|
180
187
|
}
|
|
@@ -242,7 +249,6 @@ export class TxWriter extends class_EventEmitter<ITxWriterEvents> {
|
|
|
242
249
|
.client
|
|
243
250
|
.sendTransaction(txData);
|
|
244
251
|
}
|
|
245
|
-
|
|
246
252
|
promiseEvent
|
|
247
253
|
.once('transactionHash', hash => {
|
|
248
254
|
if (tx.hash === hash) {
|
package/src/utils/$buffer.ts
CHANGED
|
@@ -109,7 +109,7 @@ class NodeBufferUtils extends BufferBase {
|
|
|
109
109
|
if (buffer instanceof Buffer) {
|
|
110
110
|
return (`0x` + buffer.toString('hex')) as TEth.Hex;
|
|
111
111
|
}
|
|
112
|
-
return (`0x` + buffer.reduce((hex, x) => {
|
|
112
|
+
return (`0x` + (buffer as Uint8Array).reduce((hex, x) => {
|
|
113
113
|
return hex + x.toString(16).padStart(2, '0');
|
|
114
114
|
}, '')) as TEth.Hex;
|
|
115
115
|
}
|
package/src/utils/$config.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
|
+
import alot from 'alot';
|
|
2
|
+
import { obj_getProperty, obj_setProperty } from 'atma-utils';
|
|
1
3
|
import { config } from '@dequanto/config/Config';
|
|
2
4
|
import { ConfigDefaults } from '@dequanto/config/ConfigDefaults';
|
|
3
|
-
import {
|
|
5
|
+
import { IConfigData } from '@dequanto/config/interface/IConfigData';
|
|
6
|
+
import { TEth } from '@dequanto/models/TEth';
|
|
7
|
+
import { $require } from './$require';
|
|
8
|
+
import { IWeb3ClientOptions } from '@dequanto/clients/interfaces/IWeb3Client';
|
|
9
|
+
import { TExplorerDefinition } from '@dequanto/models/TExplorer';
|
|
4
10
|
|
|
5
11
|
const $global = typeof global === 'undefined'
|
|
6
12
|
? window
|
|
@@ -24,8 +30,73 @@ export namespace $config {
|
|
|
24
30
|
return value ?? $default;
|
|
25
31
|
}
|
|
26
32
|
|
|
33
|
+
export function getWeb3Options (mix: TEth.Platform | number): IWeb3ClientOptions {
|
|
34
|
+
let web3 = $config.get<IConfigData['web3']>('web3');
|
|
35
|
+
let chains = $config.get<IConfigData['chains']>('chains', []);
|
|
36
|
+
let platform: TEth.Platform;
|
|
37
|
+
if (typeof mix === 'number') {
|
|
38
|
+
let chain = alot.fromObject(web3).find(x => x.value.chainId === mix);
|
|
39
|
+
if (chain != null) {
|
|
40
|
+
platform = chain.key;
|
|
41
|
+
} else {
|
|
42
|
+
let chain = chains.find(x => x.chainId === mix);
|
|
43
|
+
if (chain!= null) {
|
|
44
|
+
platform = chain.platform;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
$require.notNull(platform, `Invalid platform for chainId ${mix}`);
|
|
48
|
+
} else {
|
|
49
|
+
platform = mix;
|
|
50
|
+
}
|
|
51
|
+
if (platform.startsWith('hh:')) {
|
|
52
|
+
// Hardhat fork
|
|
53
|
+
return { platform } as any;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
let web3Config = web3[platform];
|
|
57
|
+
if (web3Config == null) {
|
|
58
|
+
// Find the configuration by the alias
|
|
59
|
+
let chain = alot
|
|
60
|
+
.fromObject(web3)
|
|
61
|
+
.filter(x => Array.isArray(x.value.aliases))
|
|
62
|
+
.find(x => x.value.aliases.includes(platform));
|
|
63
|
+
web3Config = chain?.value;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let chainConfig = chains.find(x => x.platform === platform || x.aliases?.includes(platform));
|
|
67
|
+
|
|
68
|
+
$require.notNull(web3Config || chainConfig, `Unsupported platform ${platform} for web3 client`);
|
|
69
|
+
return {
|
|
70
|
+
platform,
|
|
71
|
+
...(chainConfig ?? {}),
|
|
72
|
+
...(web3Config ?? {}),
|
|
73
|
+
} as any as IWeb3ClientOptions;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function getExplorerOptions (mix: TEth.Platform | number): TExplorerDefinition {
|
|
77
|
+
let platform = getWeb3Options(mix).platform;
|
|
78
|
+
|
|
79
|
+
let explorer = $config.get<IConfigData['blockchainExplorer']>(`blockchainExplorer`);
|
|
80
|
+
let chains = $config.get<IConfigData['chains']>('chains', []);
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
let explorerConfig = explorer[platform];
|
|
84
|
+
let chainConfig = chains.find(x => x.platform === platform || x.aliases?.includes(platform));
|
|
85
|
+
|
|
86
|
+
$require.notNull(explorerConfig || chainConfig, `Unsupported platform ${platform} for web3 client`);
|
|
87
|
+
return {
|
|
88
|
+
platform,
|
|
89
|
+
...(chainConfig?.explorers?.[0] ?? {}),
|
|
90
|
+
...(explorerConfig ?? {}),
|
|
91
|
+
} satisfies TExplorerDefinition;
|
|
92
|
+
}
|
|
93
|
+
|
|
27
94
|
export function set <T = any> (path: string, value: T) {
|
|
28
|
-
$global.app
|
|
95
|
+
if (typeof $global.app?.config?.$set === 'function') {
|
|
96
|
+
$global.app.config.$set(path, value);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
obj_setProperty(config, path, value);
|
|
29
100
|
}
|
|
30
101
|
|
|
31
102
|
/**
|
package/src/utils/$dependency.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/** ESM and CJS Loader */
|
|
2
2
|
|
|
3
|
+
import { $is } from './$is';
|
|
4
|
+
|
|
3
5
|
export namespace $dependency {
|
|
4
6
|
|
|
5
7
|
export async function load<T = any> (name: string): Promise<T> {
|
|
@@ -16,6 +18,9 @@ export namespace $dependency {
|
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
export function dirname () {
|
|
21
|
+
if ($is.BROWSER) {
|
|
22
|
+
return location.origin;
|
|
23
|
+
}
|
|
19
24
|
if (typeof __dirname !== 'undefined') {
|
|
20
25
|
return __dirname;
|
|
21
26
|
}
|
package/src/utils/$path.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { class_Uri } from 'atma-utils';
|
|
|
2
2
|
import { $config } from './$config';
|
|
3
3
|
import { env } from 'atma-io';
|
|
4
4
|
import { $dependency } from './$dependency';
|
|
5
|
+
import { $is } from './$is';
|
|
5
6
|
|
|
6
7
|
export namespace $path {
|
|
7
8
|
let root: string = null;
|
|
@@ -76,6 +77,14 @@ export namespace $path {
|
|
|
76
77
|
|
|
77
78
|
function getRoot () {
|
|
78
79
|
let base = $config.get('settings.base');
|
|
80
|
+
if ($is.BROWSER) {
|
|
81
|
+
let root = $dependency.dirname();
|
|
82
|
+
if (base != null && isAbsolute(base)) {
|
|
83
|
+
return base;
|
|
84
|
+
}
|
|
85
|
+
base ??= '/node_modules/dequanto/';
|
|
86
|
+
return class_Uri.combine(root, base);
|
|
87
|
+
}
|
|
79
88
|
if (base != null) {
|
|
80
89
|
let cwd = process.cwd();
|
|
81
90
|
return class_Uri.combine('file://' + cwd, base);
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
|
|
2
|
+
import { IEIP6963Provider } from '@dequanto/rpc/transports/compatibility/IEIP6963Provider';
|
|
3
|
+
import { class_EventEmitter } from 'atma-utils';
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
export type TGlobal = {
|
|
8
|
+
ethereum: IEIP6963Provider;
|
|
9
|
+
addEventListener: Window['addEventListener'] //(event: string, listener: Function, options?: boolean | AddEventListenerOptions): void;
|
|
10
|
+
removeEventListener: Window['removeEventListener'];
|
|
11
|
+
|
|
12
|
+
dispatchEvent (event: any): void;
|
|
13
|
+
|
|
14
|
+
localStorage?: WindowLocalStorage['localStorage']
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export namespace $ref {
|
|
18
|
+
export function getGlobal (): TGlobal {
|
|
19
|
+
if (typeof window !== 'undefined' && typeof window === 'object') {
|
|
20
|
+
const g = window as any as TGlobal;
|
|
21
|
+
return g;
|
|
22
|
+
}
|
|
23
|
+
if (typeof global !== 'undefined' && typeof global === 'object') {
|
|
24
|
+
const g = global as any as TGlobal;
|
|
25
|
+
|
|
26
|
+
if (typeof g.addEventListener !== 'function' || typeof g.dispatchEvent !== 'function') {
|
|
27
|
+
const emitter = new class_EventEmitter;
|
|
28
|
+
g.addEventListener = function (event: string, fn: (event) => any) {
|
|
29
|
+
emitter.on(event, fn);
|
|
30
|
+
};
|
|
31
|
+
g.dispatchEvent = function (event: CustomEvent) {
|
|
32
|
+
emitter.emit(event.type, event);
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return g;
|
|
37
|
+
}
|
|
38
|
+
throw new Error('No global object found');
|
|
39
|
+
}
|
|
40
|
+
}
|