@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.
- package/README.md +3 -9
- package/lib/_version.d.ts +1 -1
- package/lib/_version.js +1 -1
- package/lib/base-provider.d.ts +2 -2
- package/lib/base-provider.d.ts.map +1 -1
- package/lib/base-provider.js +300 -145
- package/lib/base-provider.js.map +1 -1
- package/lib/browser-ipc-provider.d.ts.map +1 -1
- package/lib/browser-ipc-provider.js.map +1 -1
- package/lib/browser-net.d.ts.map +1 -1
- package/lib/browser-net.js.map +1 -1
- package/lib/browser-ws.d.ts.map +1 -1
- package/lib/browser-ws.js +2 -2
- package/lib/browser-ws.js.map +1 -1
- package/lib/fallback-provider.d.ts +1 -1
- package/lib/fallback-provider.d.ts.map +1 -1
- package/lib/fallback-provider.js +86 -55
- package/lib/fallback-provider.js.map +1 -1
- package/lib/formatter.d.ts.map +1 -1
- package/lib/formatter.js +35 -29
- package/lib/formatter.js.map +1 -1
- package/lib/index.d.ts +3 -10
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +5 -28
- package/lib/index.js.map +1 -1
- package/lib/ipc-provider.d.ts +1 -1
- package/lib/ipc-provider.d.ts.map +1 -1
- package/lib/ipc-provider.js +6 -4
- package/lib/ipc-provider.js.map +1 -1
- package/lib/json-rpc-batch-provider.d.ts.map +1 -1
- package/lib/json-rpc-batch-provider.js +6 -6
- package/lib/json-rpc-batch-provider.js.map +1 -1
- package/lib/json-rpc-provider.d.ts +2 -2
- package/lib/json-rpc-provider.d.ts.map +1 -1
- package/lib/json-rpc-provider.js +167 -69
- package/lib/json-rpc-provider.js.map +1 -1
- package/lib/url-json-rpc-provider.d.ts +1 -1
- package/lib/url-json-rpc-provider.d.ts.map +1 -1
- package/lib/url-json-rpc-provider.js +4 -4
- package/lib/url-json-rpc-provider.js.map +1 -1
- package/lib/web3-provider.d.ts +1 -2
- package/lib/web3-provider.d.ts.map +1 -1
- package/lib/web3-provider.js +11 -14
- package/lib/web3-provider.js.map +1 -1
- package/lib/websocket-provider.d.ts +1 -1
- package/lib/websocket-provider.d.ts.map +1 -1
- package/lib/websocket-provider.js +21 -17
- package/lib/websocket-provider.js.map +1 -1
- package/lib/ws.d.ts.map +1 -1
- package/package.json +61 -58
- package/src.ts/_version.ts +1 -1
- package/src.ts/base-provider.ts +1418 -645
- package/src.ts/browser-ipc-provider.ts +1 -3
- package/src.ts/browser-net.ts +1 -1
- package/src.ts/browser-ws.ts +14 -8
- package/src.ts/fallback-provider.ts +375 -198
- package/src.ts/formatter.ts +161 -81
- package/src.ts/index.ts +54 -68
- package/src.ts/ipc-provider.ts +8 -7
- package/src.ts/json-rpc-batch-provider.ts +48 -44
- package/src.ts/json-rpc-provider.ts +594 -245
- package/src.ts/url-json-rpc-provider.ts +34 -15
- package/src.ts/web3-provider.ts +87 -54
- package/src.ts/websocket-provider.ts +124 -66
- package/src.ts/ws.ts +1 -1
- package/lib/alchemy-provider.d.ts +0 -17
- package/lib/alchemy-provider.d.ts.map +0 -1
- package/lib/alchemy-provider.js +0 -88
- package/lib/alchemy-provider.js.map +0 -1
- package/lib/ankr-provider.d.ts +0 -10
- package/lib/ankr-provider.d.ts.map +0 -1
- package/lib/ankr-provider.js +0 -59
- package/lib/ankr-provider.js.map +0 -1
- package/lib/cloudflare-provider.d.ts +0 -8
- package/lib/cloudflare-provider.d.ts.map +0 -1
- package/lib/cloudflare-provider.js +0 -37
- package/lib/cloudflare-provider.js.map +0 -1
- package/lib/etherscan-provider.d.ts +0 -18
- package/lib/etherscan-provider.d.ts.map +0 -1
- package/lib/etherscan-provider.js +0 -408
- package/lib/etherscan-provider.js.map +0 -1
- package/lib/infura-provider.d.ts +0 -21
- package/lib/infura-provider.d.ts.map +0 -1
- package/lib/infura-provider.js +0 -117
- package/lib/infura-provider.js.map +0 -1
- package/lib/nodesmith-provider.d.ts +0 -7
- package/lib/nodesmith-provider.d.ts.map +0 -1
- package/lib/nodesmith-provider.js +0 -44
- package/lib/nodesmith-provider.js.map +0 -1
- package/lib/pocket-provider.d.ts +0 -12
- package/lib/pocket-provider.d.ts.map +0 -1
- package/lib/pocket-provider.js +0 -78
- package/lib/pocket-provider.js.map +0 -1
- package/src.ts/alchemy-provider.ts +0 -101
- package/src.ts/ankr-provider.ts +0 -68
- package/src.ts/cloudflare-provider.ts +0 -42
- package/src.ts/etherscan-provider.ts +0 -454
- package/src.ts/infura-provider.ts +0 -143
- package/src.ts/nodesmith-provider.ts +0 -50
- package/src.ts/pocket-provider.ts +0 -93
|
@@ -1,454 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
import { BlockTag, TransactionRequest, TransactionResponse } from "@qevm/abstract-provider";
|
|
4
|
-
import { hexlify, hexValue, isHexString } from "@qevm/bytes";
|
|
5
|
-
import { Network, Networkish } from "@ethersproject/networks";
|
|
6
|
-
import { deepCopy, defineReadOnly } from "@ethersproject/properties";
|
|
7
|
-
import { accessListify } from "@qevm/transactions";
|
|
8
|
-
import { ConnectionInfo, fetchJson } from "@qevm/web";
|
|
9
|
-
|
|
10
|
-
import { showThrottleMessage } from "./formatter";
|
|
11
|
-
|
|
12
|
-
import { Logger } from "@ethersproject/logger";
|
|
13
|
-
import { version } from "./_version";
|
|
14
|
-
const logger = new Logger(version);
|
|
15
|
-
|
|
16
|
-
import { BaseProvider } from "./base-provider";
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
// The transaction has already been sanitized by the calls in Provider
|
|
20
|
-
function getTransactionPostData(transaction: TransactionRequest): Record<string, string> {
|
|
21
|
-
const result: Record<string, string> = { };
|
|
22
|
-
for (let key in transaction) {
|
|
23
|
-
if ((<any>transaction)[key] == null) { continue; }
|
|
24
|
-
let value = (<any>transaction)[key];
|
|
25
|
-
if (key === "type" && value === 0) { continue; }
|
|
26
|
-
|
|
27
|
-
// Quantity-types require no leading zero, unless 0
|
|
28
|
-
if ((<any>{ type: true, gasLimit: true, gasPrice: true, maxFeePerGs: true, maxPriorityFeePerGas: true, nonce: true, value: true })[key]) {
|
|
29
|
-
value = hexValue(hexlify(value));
|
|
30
|
-
} else if (key === "accessList") {
|
|
31
|
-
value = "[" + accessListify(value).map((set) => {
|
|
32
|
-
return `{address:"${ set.address }",storageKeys:["${ set.storageKeys.join('","') }"]}`;
|
|
33
|
-
}).join(",") + "]";
|
|
34
|
-
} else {
|
|
35
|
-
value = hexlify(value);
|
|
36
|
-
}
|
|
37
|
-
result[key] = value;
|
|
38
|
-
}
|
|
39
|
-
return result;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function getResult(result: { status?: number, message?: string, result?: any }): any {
|
|
43
|
-
// getLogs, getHistory have weird success responses
|
|
44
|
-
if (result.status == 0 && (result.message === "No records found" || result.message === "No transactions found")) {
|
|
45
|
-
return result.result;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (result.status != 1 || typeof(result.message) !== "string" || !result.message.match(/^OK/)) {
|
|
49
|
-
const error: any = new Error("invalid response");
|
|
50
|
-
error.result = JSON.stringify(result);
|
|
51
|
-
if ((result.result || "").toLowerCase().indexOf("rate limit") >= 0) {
|
|
52
|
-
error.throttleRetry = true;
|
|
53
|
-
}
|
|
54
|
-
throw error;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return result.result;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function getJsonResult(result: { jsonrpc: string, result?: any, error?: { code?: number, data?: any, message?: string} } ): any {
|
|
61
|
-
// This response indicates we are being throttled
|
|
62
|
-
if (result && (<any>result).status == 0 && (<any>result).message == "NOTOK" && (result.result || "").toLowerCase().indexOf("rate limit") >= 0) {
|
|
63
|
-
const error: any = new Error("throttled response");
|
|
64
|
-
error.result = JSON.stringify(result);
|
|
65
|
-
error.throttleRetry = true;
|
|
66
|
-
throw error;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (result.jsonrpc != "2.0") {
|
|
70
|
-
// @TODO: not any
|
|
71
|
-
const error: any = new Error("invalid response");
|
|
72
|
-
error.result = JSON.stringify(result);
|
|
73
|
-
throw error;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
if (result.error) {
|
|
77
|
-
// @TODO: not any
|
|
78
|
-
const error: any = new Error(result.error.message || "unknown error");
|
|
79
|
-
if (result.error.code) { error.code = result.error.code; }
|
|
80
|
-
if (result.error.data) { error.data = result.error.data; }
|
|
81
|
-
throw error;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
return result.result;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// The blockTag was normalized as a string by the Provider pre-perform operations
|
|
88
|
-
function checkLogTag(blockTag: string): number | "latest" {
|
|
89
|
-
if (blockTag === "pending") { throw new Error("pending not supported"); }
|
|
90
|
-
if (blockTag === "latest") { return blockTag; }
|
|
91
|
-
|
|
92
|
-
return parseInt(blockTag.substring(2), 16);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
function checkError(method: string, error: any, transaction: any): any {
|
|
97
|
-
// Undo the "convenience" some nodes are attempting to prevent backwards
|
|
98
|
-
// incompatibility; maybe for v6 consider forwarding reverts as errors
|
|
99
|
-
if (method === "call" && error.code === Logger.errors.SERVER_ERROR) {
|
|
100
|
-
const e = error.error;
|
|
101
|
-
|
|
102
|
-
// Etherscan keeps changing their string
|
|
103
|
-
if (e && (e.message.match(/reverted/i) || e.message.match(/VM execution error/i))) {
|
|
104
|
-
// Etherscan prefixes the data like "Reverted 0x1234"
|
|
105
|
-
let data = e.data;
|
|
106
|
-
if (data) { data = "0x" + data.replace(/^.*0x/i, ""); }
|
|
107
|
-
|
|
108
|
-
if (isHexString(data)) { return data; }
|
|
109
|
-
|
|
110
|
-
logger.throwError("missing revert data in call exception", Logger.errors.CALL_EXCEPTION, {
|
|
111
|
-
error, data: "0x"
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// Get the message from any nested error structure
|
|
117
|
-
let message = error.message;
|
|
118
|
-
if (error.code === Logger.errors.SERVER_ERROR) {
|
|
119
|
-
if (error.error && typeof(error.error.message) === "string") {
|
|
120
|
-
message = error.error.message;
|
|
121
|
-
} else if (typeof(error.body) === "string") {
|
|
122
|
-
message = error.body;
|
|
123
|
-
} else if (typeof(error.responseText) === "string") {
|
|
124
|
-
message = error.responseText;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
message = (message || "").toLowerCase();
|
|
128
|
-
|
|
129
|
-
// "Insufficient funds. The account you tried to send transaction from does not have enough funds. Required 21464000000000 and got: 0"
|
|
130
|
-
if (message.match(/insufficient funds/)) {
|
|
131
|
-
logger.throwError("insufficient funds for intrinsic transaction cost", Logger.errors.INSUFFICIENT_FUNDS, {
|
|
132
|
-
error, method, transaction
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// "Transaction with the same hash was already imported."
|
|
137
|
-
if (message.match(/same hash was already imported|transaction nonce is too low|nonce too low/)) {
|
|
138
|
-
logger.throwError("nonce has already been used", Logger.errors.NONCE_EXPIRED, {
|
|
139
|
-
error, method, transaction
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// "Transaction gas price is too low. There is another transaction with same nonce in the queue. Try increasing the gas price or incrementing the nonce."
|
|
144
|
-
if (message.match(/another transaction with same nonce/)) {
|
|
145
|
-
logger.throwError("replacement fee too low", Logger.errors.REPLACEMENT_UNDERPRICED, {
|
|
146
|
-
error, method, transaction
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
if (message.match(/execution failed due to an exception|execution reverted/)) {
|
|
151
|
-
logger.throwError("cannot estimate gas; transaction may fail or may require manual gas limit", Logger.errors.UNPREDICTABLE_GAS_LIMIT, {
|
|
152
|
-
error, method, transaction
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
throw error;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
export class EtherscanProvider extends BaseProvider{
|
|
160
|
-
readonly baseUrl: string;
|
|
161
|
-
readonly apiKey: string | null;
|
|
162
|
-
|
|
163
|
-
constructor(network?: Networkish, apiKey?: string) {
|
|
164
|
-
super(network);
|
|
165
|
-
|
|
166
|
-
defineReadOnly(this, "baseUrl", this.getBaseUrl());
|
|
167
|
-
defineReadOnly(this, "apiKey", apiKey || null);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
getBaseUrl(): string {
|
|
171
|
-
switch(this.network ? this.network.name: "invalid") {
|
|
172
|
-
case "homestead":
|
|
173
|
-
return "https:/\/api.etherscan.io";
|
|
174
|
-
case "goerli":
|
|
175
|
-
return "https:/\/api-goerli.etherscan.io";
|
|
176
|
-
case "sepolia":
|
|
177
|
-
return "https:/\/api-sepolia.etherscan.io";
|
|
178
|
-
case "matic":
|
|
179
|
-
return "https:/\/api.polygonscan.com";
|
|
180
|
-
case "maticmum":
|
|
181
|
-
return "https:/\/api-testnet.polygonscan.com";
|
|
182
|
-
case "arbitrum":
|
|
183
|
-
return "https:/\/api.arbiscan.io";
|
|
184
|
-
case "arbitrum-goerli":
|
|
185
|
-
return "https:/\/api-goerli.arbiscan.io";
|
|
186
|
-
case "optimism":
|
|
187
|
-
return "https:/\/api-optimistic.etherscan.io";
|
|
188
|
-
case "optimism-goerli":
|
|
189
|
-
return "https:/\/api-goerli-optimistic.etherscan.io";
|
|
190
|
-
default:
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
return logger.throwArgumentError("unsupported network", "network", this.network.name);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
getUrl(module: string, params: Record<string, string>): string {
|
|
197
|
-
const query = Object.keys(params).reduce((accum, key) => {
|
|
198
|
-
const value = params[key];
|
|
199
|
-
if (value != null) {
|
|
200
|
-
accum += `&${ key }=${ value }`
|
|
201
|
-
}
|
|
202
|
-
return accum
|
|
203
|
-
}, "");
|
|
204
|
-
const apiKey = ((this.apiKey) ? `&apikey=${ this.apiKey }`: "");
|
|
205
|
-
return `${ this.baseUrl }/api?module=${ module }${ query }${ apiKey }`;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
getPostUrl(): string {
|
|
209
|
-
return `${ this.baseUrl }/api`;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
getPostData(module: string, params: Record<string, any>): Record<string, any> {
|
|
213
|
-
params.module = module;
|
|
214
|
-
params.apikey = this.apiKey;
|
|
215
|
-
return params;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
async fetch(module: string, params: Record<string, any>, post?: boolean): Promise<any> {
|
|
219
|
-
const url = (post ? this.getPostUrl(): this.getUrl(module, params));
|
|
220
|
-
const payload = (post ? this.getPostData(module, params): null);
|
|
221
|
-
const procFunc = (module === "proxy") ? getJsonResult: getResult;
|
|
222
|
-
|
|
223
|
-
this.emit("debug", {
|
|
224
|
-
action: "request",
|
|
225
|
-
request: url,
|
|
226
|
-
provider: this
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
const connection: ConnectionInfo = {
|
|
230
|
-
url: url,
|
|
231
|
-
throttleSlotInterval: 1000,
|
|
232
|
-
throttleCallback: (attempt: number, url: string) => {
|
|
233
|
-
if (this.isCommunityResource()) {
|
|
234
|
-
showThrottleMessage();
|
|
235
|
-
}
|
|
236
|
-
return Promise.resolve(true);
|
|
237
|
-
}
|
|
238
|
-
};
|
|
239
|
-
|
|
240
|
-
let payloadStr: string = null;
|
|
241
|
-
if (payload) {
|
|
242
|
-
connection.headers = { "content-type": "application/x-www-form-urlencoded; charset=UTF-8" };
|
|
243
|
-
payloadStr = Object.keys(payload).map((key) => {
|
|
244
|
-
return `${ key }=${ payload[key] }`
|
|
245
|
-
}).join("&");
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
const result = await fetchJson(connection, payloadStr, procFunc || getJsonResult);
|
|
249
|
-
|
|
250
|
-
this.emit("debug", {
|
|
251
|
-
action: "response",
|
|
252
|
-
request: url,
|
|
253
|
-
response: deepCopy(result),
|
|
254
|
-
provider: this
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
return result;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
async detectNetwork(): Promise<Network> {
|
|
261
|
-
return this.network;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
async perform(method: string, params: any): Promise<any> {
|
|
265
|
-
|
|
266
|
-
switch (method) {
|
|
267
|
-
case "getBlockNumber":
|
|
268
|
-
return this.fetch("proxy", { action: "eth_blockNumber" });
|
|
269
|
-
|
|
270
|
-
case "getGasPrice":
|
|
271
|
-
return this.fetch("proxy", { action: "eth_gasPrice" });
|
|
272
|
-
|
|
273
|
-
case "getBalance":
|
|
274
|
-
// Returns base-10 result
|
|
275
|
-
return this.fetch("account", {
|
|
276
|
-
action: "balance",
|
|
277
|
-
address: params.address,
|
|
278
|
-
tag: params.blockTag
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
case "getTransactionCount":
|
|
282
|
-
return this.fetch("proxy", {
|
|
283
|
-
action: "eth_getTransactionCount",
|
|
284
|
-
address: params.address,
|
|
285
|
-
tag: params.blockTag
|
|
286
|
-
});
|
|
287
|
-
|
|
288
|
-
case "getCode":
|
|
289
|
-
return this.fetch("proxy", {
|
|
290
|
-
action: "eth_getCode",
|
|
291
|
-
address: params.address,
|
|
292
|
-
tag: params.blockTag
|
|
293
|
-
});
|
|
294
|
-
|
|
295
|
-
case "getStorageAt":
|
|
296
|
-
return this.fetch("proxy", {
|
|
297
|
-
action: "eth_getStorageAt",
|
|
298
|
-
address: params.address,
|
|
299
|
-
position: params.position,
|
|
300
|
-
tag: params.blockTag
|
|
301
|
-
});
|
|
302
|
-
|
|
303
|
-
case "sendTransaction":
|
|
304
|
-
return this.fetch("proxy", {
|
|
305
|
-
action: "eth_sendRawTransaction",
|
|
306
|
-
hex: params.signedTransaction
|
|
307
|
-
}, true).catch((error) => {
|
|
308
|
-
return checkError("sendTransaction", error, params.signedTransaction);
|
|
309
|
-
});
|
|
310
|
-
|
|
311
|
-
case "getBlock":
|
|
312
|
-
if (params.blockTag) {
|
|
313
|
-
return this.fetch("proxy", {
|
|
314
|
-
action: "eth_getBlockByNumber",
|
|
315
|
-
tag: params.blockTag,
|
|
316
|
-
boolean: (params.includeTransactions ? "true": "false")
|
|
317
|
-
});
|
|
318
|
-
}
|
|
319
|
-
throw new Error("getBlock by blockHash not implemented");
|
|
320
|
-
|
|
321
|
-
case "getTransaction":
|
|
322
|
-
return this.fetch("proxy", {
|
|
323
|
-
action: "eth_getTransactionByHash",
|
|
324
|
-
txhash: params.transactionHash
|
|
325
|
-
});
|
|
326
|
-
|
|
327
|
-
case "getTransactionReceipt":
|
|
328
|
-
return this.fetch("proxy", {
|
|
329
|
-
action: "eth_getTransactionReceipt",
|
|
330
|
-
txhash: params.transactionHash
|
|
331
|
-
});
|
|
332
|
-
|
|
333
|
-
case "call": {
|
|
334
|
-
if (params.blockTag !== "latest") {
|
|
335
|
-
throw new Error("EtherscanProvider does not support blockTag for call");
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
const postData = getTransactionPostData(params.transaction);
|
|
339
|
-
postData.module = "proxy";
|
|
340
|
-
postData.action = "eth_call";
|
|
341
|
-
|
|
342
|
-
try {
|
|
343
|
-
return await this.fetch("proxy", postData, true);
|
|
344
|
-
} catch (error) {
|
|
345
|
-
return checkError("call", error, params.transaction);
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
case "estimateGas": {
|
|
350
|
-
const postData = getTransactionPostData(params.transaction);
|
|
351
|
-
postData.module = "proxy";
|
|
352
|
-
postData.action = "eth_estimateGas";
|
|
353
|
-
|
|
354
|
-
try {
|
|
355
|
-
return await this.fetch("proxy", postData, true);
|
|
356
|
-
} catch (error) {
|
|
357
|
-
return checkError("estimateGas", error, params.transaction);
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
case "getLogs": {
|
|
362
|
-
const args: Record<string, any> = { action: "getLogs" }
|
|
363
|
-
|
|
364
|
-
if (params.filter.fromBlock) {
|
|
365
|
-
args.fromBlock = checkLogTag(params.filter.fromBlock);
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
if (params.filter.toBlock) {
|
|
369
|
-
args.toBlock = checkLogTag(params.filter.toBlock);
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
if (params.filter.address) {
|
|
373
|
-
args.address = params.filter.address;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
// @TODO: We can handle slightly more complicated logs using the logs API
|
|
377
|
-
if (params.filter.topics && params.filter.topics.length > 0) {
|
|
378
|
-
if (params.filter.topics.length > 1) {
|
|
379
|
-
logger.throwError("unsupported topic count", Logger.errors.UNSUPPORTED_OPERATION, { topics: params.filter.topics });
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
if (params.filter.topics.length === 1) {
|
|
383
|
-
const topic0 = params.filter.topics[0];
|
|
384
|
-
if (typeof(topic0) !== "string" || topic0.length !== 66) {
|
|
385
|
-
logger.throwError("unsupported topic format", Logger.errors.UNSUPPORTED_OPERATION, { topic0: topic0 });
|
|
386
|
-
}
|
|
387
|
-
args.topic0 = topic0;
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
const logs: Array<any> = await this.fetch("logs", args);
|
|
392
|
-
|
|
393
|
-
// Cache txHash => blockHash
|
|
394
|
-
let blocks: { [tag: string]: string } = {};
|
|
395
|
-
|
|
396
|
-
// Add any missing blockHash to the logs
|
|
397
|
-
for (let i = 0; i < logs.length; i++) {
|
|
398
|
-
const log = logs[i];
|
|
399
|
-
if (log.blockHash != null) { continue; }
|
|
400
|
-
if (blocks[log.blockNumber] == null) {
|
|
401
|
-
const block = await this.getBlock(log.blockNumber);
|
|
402
|
-
if (block) {
|
|
403
|
-
blocks[log.blockNumber] = block.hash;
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
log.blockHash = blocks[log.blockNumber];
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
return logs;
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
case "getEtherPrice":
|
|
413
|
-
if (this.network.name !== "homestead") { return 0.0; }
|
|
414
|
-
return parseFloat((await this.fetch("stats", { action: "ethprice" })).ethusd);
|
|
415
|
-
|
|
416
|
-
default:
|
|
417
|
-
break;
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
return super.perform(method, params);
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
// Note: The `page` page parameter only allows pagination within the
|
|
424
|
-
// 10,000 window available without a page and offset parameter
|
|
425
|
-
// Error: Result window is too large, PageNo x Offset size must
|
|
426
|
-
// be less than or equal to 10000
|
|
427
|
-
async getHistory(addressOrName: string | Promise<string>, startBlock?: BlockTag, endBlock?: BlockTag): Promise<Array<TransactionResponse>> {
|
|
428
|
-
const params = {
|
|
429
|
-
action: "txlist",
|
|
430
|
-
address: (await this.resolveName(addressOrName)),
|
|
431
|
-
startblock: ((startBlock == null) ? 0: startBlock),
|
|
432
|
-
endblock: ((endBlock == null) ? 99999999: endBlock),
|
|
433
|
-
sort: "asc"
|
|
434
|
-
};
|
|
435
|
-
|
|
436
|
-
const result = await this.fetch("account", params);
|
|
437
|
-
|
|
438
|
-
return result.map((tx: any) => {
|
|
439
|
-
["contractAddress", "to"].forEach(function(key) {
|
|
440
|
-
if (tx[key] == "") { delete tx[key]; }
|
|
441
|
-
});
|
|
442
|
-
if (tx.creates == null && tx.contractAddress != null) {
|
|
443
|
-
tx.creates = tx.contractAddress;
|
|
444
|
-
}
|
|
445
|
-
const item = this.formatter.transactionResponse(tx);
|
|
446
|
-
if (tx.timeStamp) { item.timestamp = parseInt(tx.timeStamp); }
|
|
447
|
-
return item;
|
|
448
|
-
});
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
isCommunityResource(): boolean {
|
|
452
|
-
return (this.apiKey == null);
|
|
453
|
-
}
|
|
454
|
-
}
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
import { Network, Networkish } from "@ethersproject/networks";
|
|
4
|
-
import { defineReadOnly } from "@ethersproject/properties";
|
|
5
|
-
import { ConnectionInfo } from "@qevm/web";
|
|
6
|
-
|
|
7
|
-
import { WebSocketProvider } from "./websocket-provider";
|
|
8
|
-
import { CommunityResourcable, showThrottleMessage } from "./formatter";
|
|
9
|
-
|
|
10
|
-
import { Logger } from "@ethersproject/logger";
|
|
11
|
-
import { version } from "./_version";
|
|
12
|
-
const logger = new Logger(version);
|
|
13
|
-
|
|
14
|
-
import { UrlJsonRpcProvider } from "./url-json-rpc-provider";
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const defaultProjectId = "84842078b09946638c03157f83405213"
|
|
18
|
-
|
|
19
|
-
export class InfuraWebSocketProvider extends WebSocketProvider implements CommunityResourcable {
|
|
20
|
-
readonly apiKey: string;
|
|
21
|
-
readonly projectId: string;
|
|
22
|
-
readonly projectSecret: string;
|
|
23
|
-
|
|
24
|
-
constructor(network?: Networkish, apiKey?: any) {
|
|
25
|
-
const provider = new InfuraProvider(network, apiKey);
|
|
26
|
-
const connection = provider.connection;
|
|
27
|
-
if (connection.password) {
|
|
28
|
-
logger.throwError("INFURA WebSocket project secrets unsupported", Logger.errors.UNSUPPORTED_OPERATION, {
|
|
29
|
-
operation: "InfuraProvider.getWebSocketProvider()"
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const url = connection.url.replace(/^http/i, "ws").replace("/v3/", "/ws/v3/");
|
|
34
|
-
super(url, network);
|
|
35
|
-
|
|
36
|
-
defineReadOnly(this, "apiKey", provider.projectId);
|
|
37
|
-
defineReadOnly(this, "projectId", provider.projectId);
|
|
38
|
-
defineReadOnly(this, "projectSecret", provider.projectSecret);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
isCommunityResource(): boolean {
|
|
42
|
-
return (this.projectId === defaultProjectId);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export class InfuraProvider extends UrlJsonRpcProvider {
|
|
47
|
-
readonly projectId: string;
|
|
48
|
-
readonly projectSecret: string;
|
|
49
|
-
|
|
50
|
-
static getWebSocketProvider(network?: Networkish, apiKey?: any): InfuraWebSocketProvider {
|
|
51
|
-
return new InfuraWebSocketProvider(network, apiKey);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
static getApiKey(apiKey: any): any {
|
|
55
|
-
const apiKeyObj: { apiKey: string, projectId: string, projectSecret: string } = {
|
|
56
|
-
apiKey: defaultProjectId,
|
|
57
|
-
projectId: defaultProjectId,
|
|
58
|
-
projectSecret: null
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
if (apiKey == null) { return apiKeyObj; }
|
|
62
|
-
|
|
63
|
-
if (typeof(apiKey) === "string") {
|
|
64
|
-
apiKeyObj.projectId = apiKey;
|
|
65
|
-
|
|
66
|
-
} else if (apiKey.projectSecret != null) {
|
|
67
|
-
logger.assertArgument((typeof(apiKey.projectId) === "string"),
|
|
68
|
-
"projectSecret requires a projectId", "projectId", apiKey.projectId);
|
|
69
|
-
logger.assertArgument((typeof(apiKey.projectSecret) === "string"),
|
|
70
|
-
"invalid projectSecret", "projectSecret", "[REDACTED]");
|
|
71
|
-
|
|
72
|
-
apiKeyObj.projectId = apiKey.projectId;
|
|
73
|
-
apiKeyObj.projectSecret = apiKey.projectSecret;
|
|
74
|
-
|
|
75
|
-
} else if (apiKey.projectId) {
|
|
76
|
-
apiKeyObj.projectId = apiKey.projectId;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
apiKeyObj.apiKey = apiKeyObj.projectId;
|
|
80
|
-
|
|
81
|
-
return apiKeyObj;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
static getUrl(network: Network, apiKey: any): ConnectionInfo {
|
|
85
|
-
let host: string = null;
|
|
86
|
-
switch(network ? network.name: "unknown") {
|
|
87
|
-
case "homestead":
|
|
88
|
-
host = "mainnet.infura.io";
|
|
89
|
-
break;
|
|
90
|
-
case "goerli":
|
|
91
|
-
host = "goerli.infura.io";
|
|
92
|
-
break;
|
|
93
|
-
case "sepolia":
|
|
94
|
-
host = "sepolia.infura.io";
|
|
95
|
-
break;
|
|
96
|
-
case "matic":
|
|
97
|
-
host = "polygon-mainnet.infura.io";
|
|
98
|
-
break;
|
|
99
|
-
case "maticmum":
|
|
100
|
-
host = "polygon-mumbai.infura.io";
|
|
101
|
-
break;
|
|
102
|
-
case "optimism":
|
|
103
|
-
host = "optimism-mainnet.infura.io";
|
|
104
|
-
break;
|
|
105
|
-
case "optimism-goerli":
|
|
106
|
-
host = "optimism-goerli.infura.io";
|
|
107
|
-
break;
|
|
108
|
-
case "arbitrum":
|
|
109
|
-
host = "arbitrum-mainnet.infura.io";
|
|
110
|
-
break;
|
|
111
|
-
case "arbitrum-goerli":
|
|
112
|
-
host = "arbitrum-goerli.infura.io";
|
|
113
|
-
break;
|
|
114
|
-
default:
|
|
115
|
-
logger.throwError("unsupported network", Logger.errors.INVALID_ARGUMENT, {
|
|
116
|
-
argument: "network",
|
|
117
|
-
value: network
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const connection: ConnectionInfo = {
|
|
122
|
-
allowGzip: true,
|
|
123
|
-
url: ("https:/" + "/" + host + "/v3/" + apiKey.projectId),
|
|
124
|
-
throttleCallback: (attempt: number, url: string) => {
|
|
125
|
-
if (apiKey.projectId === defaultProjectId) {
|
|
126
|
-
showThrottleMessage();
|
|
127
|
-
}
|
|
128
|
-
return Promise.resolve(true);
|
|
129
|
-
}
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
if (apiKey.projectSecret != null) {
|
|
133
|
-
connection.user = "";
|
|
134
|
-
connection.password = apiKey.projectSecret
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
return connection;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
isCommunityResource(): boolean {
|
|
141
|
-
return (this.projectId === defaultProjectId);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
/* istanbul ignore file */
|
|
2
|
-
|
|
3
|
-
"use strict";
|
|
4
|
-
|
|
5
|
-
import { Network } from "@ethersproject/networks";
|
|
6
|
-
import { UrlJsonRpcProvider } from "./url-json-rpc-provider";
|
|
7
|
-
|
|
8
|
-
import { Logger } from "@ethersproject/logger";
|
|
9
|
-
import { version } from "./_version";
|
|
10
|
-
const logger = new Logger(version);
|
|
11
|
-
|
|
12
|
-
// Special API key provided by Nodesmith for ethers.js
|
|
13
|
-
const defaultApiKey = "ETHERS_JS_SHARED";
|
|
14
|
-
|
|
15
|
-
export class NodesmithProvider extends UrlJsonRpcProvider {
|
|
16
|
-
|
|
17
|
-
static getApiKey(apiKey: any): any {
|
|
18
|
-
if (apiKey && typeof(apiKey) !== "string") {
|
|
19
|
-
logger.throwArgumentError("invalid apiKey", "apiKey", apiKey);
|
|
20
|
-
}
|
|
21
|
-
return apiKey || defaultApiKey;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
static getUrl(network: Network, apiKey?: any): string {
|
|
25
|
-
logger.warn("NodeSmith will be discontinued on 2019-12-20; please migrate to another platform.");
|
|
26
|
-
|
|
27
|
-
let host = null;
|
|
28
|
-
switch (network.name) {
|
|
29
|
-
case "homestead":
|
|
30
|
-
host = "https://ethereum.api.nodesmith.io/v1/mainnet/jsonrpc";
|
|
31
|
-
break;
|
|
32
|
-
case "ropsten":
|
|
33
|
-
host = "https://ethereum.api.nodesmith.io/v1/ropsten/jsonrpc";
|
|
34
|
-
break;
|
|
35
|
-
case "rinkeby":
|
|
36
|
-
host = "https://ethereum.api.nodesmith.io/v1/rinkeby/jsonrpc";
|
|
37
|
-
break;
|
|
38
|
-
case "goerli":
|
|
39
|
-
host = "https://ethereum.api.nodesmith.io/v1/goerli/jsonrpc";
|
|
40
|
-
break;
|
|
41
|
-
case "kovan":
|
|
42
|
-
host = "https://ethereum.api.nodesmith.io/v1/kovan/jsonrpc";
|
|
43
|
-
break;
|
|
44
|
-
default:
|
|
45
|
-
logger.throwArgumentError("unsupported network", "network", arguments[0]);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return (host + "?apiKey=" + apiKey);
|
|
49
|
-
}
|
|
50
|
-
}
|