@qevm/providers 1.0.2 → 1.0.3

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 (100) hide show
  1. package/README.md +3 -9
  2. package/lib/_version.d.ts +1 -1
  3. package/lib/_version.js +1 -1
  4. package/lib/base-provider.d.ts +2 -2
  5. package/lib/base-provider.d.ts.map +1 -1
  6. package/lib/base-provider.js +300 -145
  7. package/lib/base-provider.js.map +1 -1
  8. package/lib/browser-ipc-provider.d.ts.map +1 -1
  9. package/lib/browser-ipc-provider.js.map +1 -1
  10. package/lib/browser-net.d.ts.map +1 -1
  11. package/lib/browser-net.js.map +1 -1
  12. package/lib/browser-ws.d.ts.map +1 -1
  13. package/lib/browser-ws.js +2 -2
  14. package/lib/browser-ws.js.map +1 -1
  15. package/lib/fallback-provider.d.ts +1 -1
  16. package/lib/fallback-provider.d.ts.map +1 -1
  17. package/lib/fallback-provider.js +86 -55
  18. package/lib/fallback-provider.js.map +1 -1
  19. package/lib/formatter.d.ts.map +1 -1
  20. package/lib/formatter.js +35 -29
  21. package/lib/formatter.js.map +1 -1
  22. package/lib/index.d.ts +3 -10
  23. package/lib/index.d.ts.map +1 -1
  24. package/lib/index.js +5 -28
  25. package/lib/index.js.map +1 -1
  26. package/lib/ipc-provider.d.ts +1 -1
  27. package/lib/ipc-provider.d.ts.map +1 -1
  28. package/lib/ipc-provider.js +6 -4
  29. package/lib/ipc-provider.js.map +1 -1
  30. package/lib/json-rpc-batch-provider.d.ts.map +1 -1
  31. package/lib/json-rpc-batch-provider.js +6 -6
  32. package/lib/json-rpc-batch-provider.js.map +1 -1
  33. package/lib/json-rpc-provider.d.ts +2 -2
  34. package/lib/json-rpc-provider.d.ts.map +1 -1
  35. package/lib/json-rpc-provider.js +167 -69
  36. package/lib/json-rpc-provider.js.map +1 -1
  37. package/lib/url-json-rpc-provider.d.ts +1 -1
  38. package/lib/url-json-rpc-provider.d.ts.map +1 -1
  39. package/lib/url-json-rpc-provider.js +4 -4
  40. package/lib/url-json-rpc-provider.js.map +1 -1
  41. package/lib/web3-provider.d.ts +1 -2
  42. package/lib/web3-provider.d.ts.map +1 -1
  43. package/lib/web3-provider.js +11 -14
  44. package/lib/web3-provider.js.map +1 -1
  45. package/lib/websocket-provider.d.ts +1 -1
  46. package/lib/websocket-provider.d.ts.map +1 -1
  47. package/lib/websocket-provider.js +21 -17
  48. package/lib/websocket-provider.js.map +1 -1
  49. package/lib/ws.d.ts.map +1 -1
  50. package/package.json +61 -58
  51. package/src.ts/_version.ts +1 -1
  52. package/src.ts/base-provider.ts +1418 -645
  53. package/src.ts/browser-ipc-provider.ts +1 -3
  54. package/src.ts/browser-net.ts +1 -1
  55. package/src.ts/browser-ws.ts +14 -8
  56. package/src.ts/fallback-provider.ts +375 -198
  57. package/src.ts/formatter.ts +161 -81
  58. package/src.ts/index.ts +54 -68
  59. package/src.ts/ipc-provider.ts +8 -7
  60. package/src.ts/json-rpc-batch-provider.ts +48 -44
  61. package/src.ts/json-rpc-provider.ts +594 -245
  62. package/src.ts/url-json-rpc-provider.ts +34 -15
  63. package/src.ts/web3-provider.ts +87 -54
  64. package/src.ts/websocket-provider.ts +124 -66
  65. package/src.ts/ws.ts +1 -1
  66. package/lib/alchemy-provider.d.ts +0 -17
  67. package/lib/alchemy-provider.d.ts.map +0 -1
  68. package/lib/alchemy-provider.js +0 -88
  69. package/lib/alchemy-provider.js.map +0 -1
  70. package/lib/ankr-provider.d.ts +0 -10
  71. package/lib/ankr-provider.d.ts.map +0 -1
  72. package/lib/ankr-provider.js +0 -59
  73. package/lib/ankr-provider.js.map +0 -1
  74. package/lib/cloudflare-provider.d.ts +0 -8
  75. package/lib/cloudflare-provider.d.ts.map +0 -1
  76. package/lib/cloudflare-provider.js +0 -37
  77. package/lib/cloudflare-provider.js.map +0 -1
  78. package/lib/etherscan-provider.d.ts +0 -18
  79. package/lib/etherscan-provider.d.ts.map +0 -1
  80. package/lib/etherscan-provider.js +0 -408
  81. package/lib/etherscan-provider.js.map +0 -1
  82. package/lib/infura-provider.d.ts +0 -21
  83. package/lib/infura-provider.d.ts.map +0 -1
  84. package/lib/infura-provider.js +0 -117
  85. package/lib/infura-provider.js.map +0 -1
  86. package/lib/nodesmith-provider.d.ts +0 -7
  87. package/lib/nodesmith-provider.d.ts.map +0 -1
  88. package/lib/nodesmith-provider.js +0 -44
  89. package/lib/nodesmith-provider.js.map +0 -1
  90. package/lib/pocket-provider.d.ts +0 -12
  91. package/lib/pocket-provider.d.ts.map +0 -1
  92. package/lib/pocket-provider.js +0 -78
  93. package/lib/pocket-provider.js.map +0 -1
  94. package/src.ts/alchemy-provider.ts +0 -101
  95. package/src.ts/ankr-provider.ts +0 -68
  96. package/src.ts/cloudflare-provider.ts +0 -42
  97. package/src.ts/etherscan-provider.ts +0 -454
  98. package/src.ts/infura-provider.ts +0 -143
  99. package/src.ts/nodesmith-provider.ts +0 -50
  100. package/src.ts/pocket-provider.ts +0 -93
@@ -1,30 +1,38 @@
1
1
  "use strict";
2
2
 
3
- import { Block, TransactionReceipt, TransactionResponse } from "@qevm/abstract-provider";
3
+ import {
4
+ Block,
5
+ TransactionReceipt,
6
+ TransactionResponse,
7
+ } from "@qevm/abstract-provider";
4
8
  import { getAddress, getContractAddress } from "@qevm/address";
5
9
  import { BigNumber } from "@qevm/bignumber";
6
- import { hexDataLength, hexDataSlice, hexValue, hexZeroPad, isHexString } from "@qevm/bytes";
10
+ import { hexDataLength, hexValue, hexZeroPad, isHexString } from "@qevm/bytes";
7
11
  import { AddressZero } from "@qevm/constants";
8
- import { shallowCopy } from "@ethersproject/properties";
9
- import { AccessList, accessListify, parse as parseTransaction } from "@qevm/transactions";
10
-
11
- import { Logger } from "@ethersproject/logger";
12
+ import { shallowCopy } from "@qevm/properties";
13
+ import {
14
+ AccessList,
15
+ accessListify,
16
+ parse as parseTransaction,
17
+ } from "@qevm/transactions";
18
+
19
+ import { Logger } from "@qevm/logger";
12
20
  import { version } from "./_version";
13
21
  const logger = new Logger(version);
14
22
 
15
23
  export type FormatFunc = (value: any) => any;
16
24
 
17
- export type FormatFuncs = { [ key: string ]: FormatFunc };
25
+ export type FormatFuncs = { [key: string]: FormatFunc };
18
26
 
19
27
  export type Formats = {
20
- transaction: FormatFuncs,
21
- transactionRequest: FormatFuncs,
22
- receipt: FormatFuncs,
23
- receiptLog: FormatFuncs,
24
- block: FormatFuncs,
25
- blockWithTransactions: FormatFuncs,
26
- filter: FormatFuncs,
27
- filterLog: FormatFuncs,
28
+ transaction: FormatFuncs;
29
+ transactionRequest: FormatFuncs;
30
+ receipt: FormatFuncs;
31
+ receiptLog: FormatFuncs;
32
+ block: FormatFuncs;
33
+ blockWithTransactions: FormatFuncs;
34
+ filter: FormatFuncs;
35
+ filterLog: FormatFuncs;
28
36
  };
29
37
 
30
38
  export class Formatter {
@@ -35,7 +43,7 @@ export class Formatter {
35
43
  }
36
44
 
37
45
  getDefaultFormats(): Formats {
38
- const formats: Formats = <Formats>({ });
46
+ const formats: Formats = <Formats>{};
39
47
 
40
48
  const address = this.address.bind(this);
41
49
  const bigNumber = this.bigNumber.bind(this);
@@ -46,7 +54,9 @@ export class Formatter {
46
54
  const number = this.number.bind(this);
47
55
  const type = this.type.bind(this);
48
56
 
49
- const strictData = (v: any) => { return this.data(v, true); };
57
+ const strictData = (v: any) => {
58
+ return this.data(v, true);
59
+ };
50
60
 
51
61
  formats.transaction = {
52
62
  hash: hash,
@@ -116,7 +126,7 @@ export class Formatter {
116
126
  // should be allowNull(hash), but broken-EIP-658 support is handled in receipt
117
127
  root: Formatter.allowNull(hex),
118
128
  gasUsed: bigNumber,
119
- logsBloom: Formatter.allowNull(data),// @TODO: should this be data?
129
+ logsBloom: Formatter.allowNull(data), // @TODO: should this be data?
120
130
  blockHash: hash,
121
131
  transactionHash: hash,
122
132
  logs: Formatter.arrayOf(this.receiptLog.bind(this)),
@@ -125,7 +135,7 @@ export class Formatter {
125
135
  cumulativeGasUsed: bigNumber,
126
136
  effectiveGasPrice: Formatter.allowNull(bigNumber),
127
137
  status: Formatter.allowNull(number),
128
- type: type
138
+ type: type,
129
139
  };
130
140
 
131
141
  formats.block = {
@@ -145,11 +155,13 @@ export class Formatter {
145
155
 
146
156
  transactions: Formatter.allowNull(Formatter.arrayOf(hash)),
147
157
 
148
- baseFeePerGas: Formatter.allowNull(bigNumber)
158
+ baseFeePerGas: Formatter.allowNull(bigNumber),
149
159
  };
150
160
 
151
161
  formats.blockWithTransactions = shallowCopy(formats.block);
152
- formats.blockWithTransactions.transactions = Formatter.allowNull(Formatter.arrayOf(this.transactionResponse.bind(this)));
162
+ formats.blockWithTransactions.transactions = Formatter.allowNull(
163
+ Formatter.arrayOf(this.transactionResponse.bind(this)),
164
+ );
153
165
 
154
166
  formats.filter = {
155
167
  fromBlock: Formatter.allowNull(blockTag, undefined),
@@ -185,12 +197,16 @@ export class Formatter {
185
197
  // Requires a BigNumberish that is within the IEEE754 safe integer range; returns a number
186
198
  // Strict! Used on input.
187
199
  number(number: any): number {
188
- if (number === "0x") { return 0; }
200
+ if (number === "0x") {
201
+ return 0;
202
+ }
189
203
  return BigNumber.from(number).toNumber();
190
204
  }
191
205
 
192
206
  type(number: any): number {
193
- if (number === "0x" || number == null) { return 0; }
207
+ if (number === "0x" || number == null) {
208
+ return 0;
209
+ }
194
210
  return BigNumber.from(number).toNumber();
195
211
  }
196
212
 
@@ -201,20 +217,28 @@ export class Formatter {
201
217
 
202
218
  // Requires a boolean, "true" or "false"; returns a boolean
203
219
  boolean(value: any): boolean {
204
- if (typeof(value) === "boolean") { return value; }
205
- if (typeof(value) === "string") {
220
+ if (typeof value === "boolean") {
221
+ return value;
222
+ }
223
+ if (typeof value === "string") {
206
224
  value = value.toLowerCase();
207
- if (value === "true") { return true; }
208
- if (value === "false") { return false; }
225
+ if (value === "true") {
226
+ return true;
227
+ }
228
+ if (value === "false") {
229
+ return false;
230
+ }
209
231
  }
210
232
  throw new Error("invalid boolean - " + value);
211
233
  }
212
234
 
213
235
  hex(value: any, strict?: boolean): string {
214
- if (typeof(value) === "string") {
215
- if (!strict && value.substring(0, 2) !== "0x") { value = "0x" + value; }
236
+ if (typeof value === "string") {
237
+ if (!strict && value.substring(0, 2) !== "0x") {
238
+ value = "0x" + value;
239
+ }
216
240
  if (isHexString(value)) {
217
- return value.toLowerCase();
241
+ return value.toLowerCase();
218
242
  }
219
243
  }
220
244
  return logger.throwArgumentError("invalid hash", "value", value);
@@ -222,7 +246,7 @@ export class Formatter {
222
246
 
223
247
  data(value: any, strict?: boolean): string {
224
248
  const result = this.hex(value, strict);
225
- if ((result.length % 2) !== 0) {
249
+ if (result.length % 2 !== 0) {
226
250
  throw new Error("invalid data; odd-length - " + value);
227
251
  }
228
252
  return result;
@@ -235,9 +259,11 @@ export class Formatter {
235
259
  }
236
260
 
237
261
  callAddress(value: any): string {
238
- if (!isHexString(value, 32)) { return null; }
239
- const address = getAddress(hexDataSlice(value, 12));
240
- return (address === AddressZero) ? null: address;
262
+ if (!isHexString(value, 32)) {
263
+ return null;
264
+ }
265
+ const address = getAddress(value);
266
+ return address === AddressZero ? null : address;
241
267
  }
242
268
 
243
269
  contractAddress(value: any): string {
@@ -246,17 +272,25 @@ export class Formatter {
246
272
 
247
273
  // Strict! Used on input.
248
274
  blockTag(blockTag: any): string {
249
- if (blockTag == null) { return "latest"; }
275
+ if (blockTag == null) {
276
+ return "latest";
277
+ }
250
278
 
251
- if (blockTag === "earliest") { return "0x0"; }
279
+ if (blockTag === "earliest") {
280
+ return "0x0";
281
+ }
252
282
 
253
283
  switch (blockTag) {
254
- case "earliest": return "0x0";
255
- case "latest": case "pending": case "safe": case "finalized":
284
+ case "earliest":
285
+ return "0x0";
286
+ case "latest":
287
+ case "pending":
288
+ case "safe":
289
+ case "finalized":
256
290
  return blockTag;
257
291
  }
258
292
 
259
- if (typeof(blockTag) === "number" || isHexString(blockTag)) {
293
+ if (typeof blockTag === "number" || isHexString(blockTag)) {
260
294
  return hexValue(<number | string>blockTag);
261
295
  }
262
296
 
@@ -274,15 +308,17 @@ export class Formatter {
274
308
 
275
309
  // Returns the difficulty as a number, or if too large (i.e. PoA network) null
276
310
  difficulty(value: any): number {
277
- if (value == null) { return null; }
311
+ if (value == null) {
312
+ return null;
313
+ }
278
314
 
279
315
  const v = BigNumber.from(value);
280
316
 
281
317
  try {
282
318
  return v.toNumber();
283
- } catch (error) { }
319
+ } catch (error) {}
284
320
 
285
- return null;
321
+ return null;
286
322
  }
287
323
 
288
324
  uint256(value: any): string {
@@ -297,9 +333,11 @@ export class Formatter {
297
333
  value.miner = value.author;
298
334
  }
299
335
  // The difficulty may need to come from _difficulty in recursed blocks
300
- const difficulty = (value._difficulty != null) ? value._difficulty: value.difficulty;
336
+ const difficulty =
337
+ value._difficulty != null ? value._difficulty : value.difficulty;
301
338
  const result = Formatter.check(format, value);
302
- result._difficulty = ((difficulty == null) ? null: BigNumber.from(difficulty));
339
+ result._difficulty =
340
+ difficulty == null ? null : BigNumber.from(difficulty);
303
341
  return result;
304
342
  }
305
343
 
@@ -317,7 +355,6 @@ export class Formatter {
317
355
  }
318
356
 
319
357
  transactionResponse(transaction: any): TransactionResponse {
320
-
321
358
  // Rename gas to gasLimit
322
359
  if (transaction.gas != null && transaction.gasLimit == null) {
323
360
  transaction.gasLimit = transaction.gas;
@@ -326,7 +363,8 @@ export class Formatter {
326
363
  // Some clients (TestRPC) do strange things like return 0x0 for the
327
364
  // 0 address; correct this to be a real address
328
365
  if (transaction.to && BigNumber.from(transaction.to).isZero()) {
329
- transaction.to = "0x0000000000000000000000000000000000000000";
366
+ transaction.to =
367
+ "0x0000000000000000000000000000000000000000000000000000000000000000";
330
368
  }
331
369
 
332
370
  // Rename input to data
@@ -339,11 +377,17 @@ export class Formatter {
339
377
  transaction.creates = this.contractAddress(transaction);
340
378
  }
341
379
 
342
- if ((transaction.type === 1 || transaction.type === 2)&& transaction.accessList == null) {
343
- transaction.accessList = [ ];
380
+ if (
381
+ (transaction.type === 1 || transaction.type === 2) &&
382
+ transaction.accessList == null
383
+ ) {
384
+ transaction.accessList = [];
344
385
  }
345
386
 
346
- const result: TransactionResponse = Formatter.check(this.formats.transaction, transaction);
387
+ const result: TransactionResponse = Formatter.check(
388
+ this.formats.transaction,
389
+ transaction,
390
+ );
347
391
 
348
392
  if (transaction.chainId != null) {
349
393
  let chainId = transaction.chainId;
@@ -353,7 +397,6 @@ export class Formatter {
353
397
  }
354
398
 
355
399
  result.chainId = chainId;
356
-
357
400
  } else {
358
401
  let chainId = transaction.networkId;
359
402
 
@@ -366,11 +409,13 @@ export class Formatter {
366
409
  chainId = BigNumber.from(chainId).toNumber();
367
410
  }
368
411
 
369
- if (typeof(chainId) !== "number") {
412
+ if (typeof chainId !== "number") {
370
413
  chainId = 0;
371
414
  }
372
415
 
373
- if (typeof(chainId) !== "number") { chainId = 0; }
416
+ if (typeof chainId !== "number") {
417
+ chainId = 0;
418
+ }
374
419
 
375
420
  result.chainId = chainId;
376
421
  }
@@ -392,7 +437,10 @@ export class Formatter {
392
437
  }
393
438
 
394
439
  receipt(value: any): TransactionReceipt {
395
- const result: TransactionReceipt = Formatter.check(this.formats.receipt, value);
440
+ const result: TransactionReceipt = Formatter.check(
441
+ this.formats.receipt,
442
+ value,
443
+ );
396
444
 
397
445
  // RSK incorrectly implemented EIP-658, so we munge things a bit here for it
398
446
  if (result.root != null) {
@@ -401,17 +449,29 @@ export class Formatter {
401
449
  const value = BigNumber.from(result.root).toNumber();
402
450
  if (value === 0 || value === 1) {
403
451
  // Make sure if both are specified, they match
404
- if (result.status != null && (result.status !== value)) {
405
- logger.throwArgumentError("alt-root-status/status mismatch", "value", { root: result.root, status: result.status });
452
+ if (result.status != null && result.status !== value) {
453
+ logger.throwArgumentError(
454
+ "alt-root-status/status mismatch",
455
+ "value",
456
+ { root: result.root, status: result.status },
457
+ );
406
458
  }
407
459
  result.status = value;
408
460
  delete result.root;
409
461
  } else {
410
- logger.throwArgumentError("invalid alt-root-status", "value.root", result.root);
462
+ logger.throwArgumentError(
463
+ "invalid alt-root-status",
464
+ "value.root",
465
+ result.root,
466
+ );
411
467
  }
412
468
  } else if (result.root.length !== 66) {
413
469
  // Must be a valid bytes32
414
- logger.throwArgumentError("invalid root hash", "value.root", result.root);
470
+ logger.throwArgumentError(
471
+ "invalid root hash",
472
+ "value.root",
473
+ result.root,
474
+ );
415
475
  }
416
476
  }
417
477
 
@@ -425,7 +485,6 @@ export class Formatter {
425
485
  topics(value: any): any {
426
486
  if (Array.isArray(value)) {
427
487
  return value.map((v) => this.topics(v));
428
-
429
488
  } else if (value != null) {
430
489
  return this.hash(value, true);
431
490
  }
@@ -441,12 +500,14 @@ export class Formatter {
441
500
  return Formatter.check(this.formats.filterLog, value);
442
501
  }
443
502
 
444
- static check(format: { [ name: string ]: FormatFunc }, object: any): any {
503
+ static check(format: { [name: string]: FormatFunc }, object: any): any {
445
504
  const result: any = {};
446
505
  for (const key in format) {
447
506
  try {
448
507
  const value = format[key](object[key]);
449
- if (value !== undefined) { result[key] = value; }
508
+ if (value !== undefined) {
509
+ result[key] = value;
510
+ }
450
511
  } catch (error) {
451
512
  error.checkKey = key;
452
513
  error.checkValue = object[key];
@@ -458,33 +519,39 @@ export class Formatter {
458
519
 
459
520
  // if value is null-ish, nullValue is returned
460
521
  static allowNull(format: FormatFunc, nullValue?: any): FormatFunc {
461
- return (function(value: any) {
462
- if (value == null) { return nullValue; }
522
+ return function (value: any) {
523
+ if (value == null) {
524
+ return nullValue;
525
+ }
463
526
  return format(value);
464
- });
527
+ };
465
528
  }
466
529
 
467
530
  // If value is false-ish, replaceValue is returned
468
531
  static allowFalsish(format: FormatFunc, replaceValue: any): FormatFunc {
469
- return (function(value: any) {
470
- if (!value) { return replaceValue; }
532
+ return function (value: any) {
533
+ if (!value) {
534
+ return replaceValue;
535
+ }
471
536
  return format(value);
472
- });
537
+ };
473
538
  }
474
539
 
475
540
  // Requires an Array satisfying check
476
541
  static arrayOf(format: FormatFunc): FormatFunc {
477
- return (function(array: any): Array<any> {
478
- if (!Array.isArray(array)) { throw new Error("not an array"); }
542
+ return function (array: any): Array<any> {
543
+ if (!Array.isArray(array)) {
544
+ throw new Error("not an array");
545
+ }
479
546
 
480
547
  const result: any = [];
481
548
 
482
- array.forEach(function(value) {
549
+ array.forEach(function (value) {
483
550
  result.push(format(value));
484
551
  });
485
552
 
486
553
  return result;
487
- });
554
+ };
488
555
  }
489
556
  }
490
557
 
@@ -492,31 +559,44 @@ export interface CommunityResourcable {
492
559
  isCommunityResource(): boolean;
493
560
  }
494
561
 
495
- export function isCommunityResourcable(value: any): value is CommunityResourcable {
496
- return (value && typeof(value.isCommunityResource) === "function");
562
+ export function isCommunityResourcable(
563
+ value: any,
564
+ ): value is CommunityResourcable {
565
+ return value && typeof value.isCommunityResource === "function";
497
566
  }
498
567
 
499
568
  export function isCommunityResource(value: any): boolean {
500
- return (isCommunityResourcable(value) && value.isCommunityResource());
569
+ return isCommunityResourcable(value) && value.isCommunityResource();
501
570
  }
502
571
 
503
572
  // Show the throttle message only once
504
573
  let throttleMessage = false;
505
574
  export function showThrottleMessage() {
506
- if (throttleMessage) { return; }
575
+ if (throttleMessage) {
576
+ return;
577
+ }
507
578
  throttleMessage = true;
508
579
 
509
- console.log("========= NOTICE =========")
580
+ console.log("========= NOTICE =========");
510
581
  console.log("Request-Rate Exceeded (this message will not be repeated)");
511
582
  console.log("");
512
- console.log("The default API keys for each service are provided as a highly-throttled,");
513
- console.log("community resource for low-traffic projects and early prototyping.");
583
+ console.log(
584
+ "The default API keys for each service are provided as a highly-throttled,",
585
+ );
586
+ console.log(
587
+ "community resource for low-traffic projects and early prototyping.",
588
+ );
514
589
  console.log("");
515
- console.log("While your application will continue to function, we highly recommended");
516
- console.log("signing up for your own API keys to improve performance, increase your");
517
- console.log("request rate/limit and enable other perks, such as metrics and advanced APIs.");
590
+ console.log(
591
+ "While your application will continue to function, we highly recommended",
592
+ );
593
+ console.log(
594
+ "signing up for your own API keys to improve performance, increase your",
595
+ );
596
+ console.log(
597
+ "request rate/limit and enable other perks, such as metrics and advanced APIs.",
598
+ );
518
599
  console.log("");
519
600
  console.log("For more details: https:/\/docs.ethers.io/api-keys/");
520
601
  console.log("==========================");
521
602
  }
522
-