1 | "use strict";
|
2 | var __extends = (this && this.__extends) || (function () {
|
3 | var extendStatics = function (d, b) {
|
4 | extendStatics = Object.setPrototypeOf ||
|
5 | ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
6 | function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
7 | return extendStatics(d, b);
|
8 | };
|
9 | return function (d, b) {
|
10 | if (typeof b !== "function" && b !== null)
|
11 | throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
12 | extendStatics(d, b);
|
13 | function __() { this.constructor = d; }
|
14 | d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
15 | };
|
16 | })();
|
17 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
18 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
19 | return new (P || (P = Promise))(function (resolve, reject) {
|
20 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
21 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
22 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
23 | step((generator = generator.apply(thisArg, _arguments || [])).next());
|
24 | });
|
25 | };
|
26 | var __generator = (this && this.__generator) || function (thisArg, body) {
|
27 | var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
28 | return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
29 | function verb(n) { return function (v) { return step([n, v]); }; }
|
30 | function step(op) {
|
31 | if (f) throw new TypeError("Generator is already executing.");
|
32 | while (_) try {
|
33 | if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
34 | if (y = 0, t) op = [op[0] & 2, t.value];
|
35 | switch (op[0]) {
|
36 | case 0: case 1: t = op; break;
|
37 | case 4: _.label++; return { value: op[1], done: false };
|
38 | case 5: _.label++; y = op[1]; op = [0]; continue;
|
39 | case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
40 | default:
|
41 | if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
42 | if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
43 | if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
44 | if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
45 | if (t[2]) _.ops.pop();
|
46 | _.trys.pop(); continue;
|
47 | }
|
48 | op = body.call(thisArg, _);
|
49 | } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
50 | if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
51 | }
|
52 | };
|
53 | Object.defineProperty(exports, "__esModule", { value: true });
|
54 | exports.EtherscanProvider = void 0;
|
55 | var bytes_1 = require("@ethersproject/bytes");
|
56 | var properties_1 = require("@ethersproject/properties");
|
57 | var transactions_1 = require("@ethersproject/transactions");
|
58 | var web_1 = require("@ethersproject/web");
|
59 | var formatter_1 = require("./formatter");
|
60 | var logger_1 = require("@ethersproject/logger");
|
61 | var _version_1 = require("./_version");
|
62 | var logger = new logger_1.Logger(_version_1.version);
|
63 | var base_provider_1 = require("./base-provider");
|
64 |
|
65 | function getTransactionPostData(transaction) {
|
66 | var result = {};
|
67 | for (var key in transaction) {
|
68 | if (transaction[key] == null) {
|
69 | continue;
|
70 | }
|
71 | var value = transaction[key];
|
72 | if (key === "type" && value === 0) {
|
73 | continue;
|
74 | }
|
75 |
|
76 | if ({ type: true, gasLimit: true, gasPrice: true, maxFeePerGs: true, maxPriorityFeePerGas: true, nonce: true, value: true }[key]) {
|
77 | value = (0, bytes_1.hexValue)((0, bytes_1.hexlify)(value));
|
78 | }
|
79 | else if (key === "accessList") {
|
80 | value = "[" + (0, transactions_1.accessListify)(value).map(function (set) {
|
81 | return "{address:\"" + set.address + "\",storageKeys:[\"" + set.storageKeys.join('","') + "\"]}";
|
82 | }).join(",") + "]";
|
83 | }
|
84 | else {
|
85 | value = (0, bytes_1.hexlify)(value);
|
86 | }
|
87 | result[key] = value;
|
88 | }
|
89 | return result;
|
90 | }
|
91 | function getResult(result) {
|
92 |
|
93 | if (result.status == 0 && (result.message === "No records found" || result.message === "No transactions found")) {
|
94 | return result.result;
|
95 | }
|
96 | if (result.status != 1 || typeof (result.message) !== "string" || !result.message.match(/^OK/)) {
|
97 | var error = new Error("invalid response");
|
98 | error.result = JSON.stringify(result);
|
99 | if ((result.result || "").toLowerCase().indexOf("rate limit") >= 0) {
|
100 | error.throttleRetry = true;
|
101 | }
|
102 | throw error;
|
103 | }
|
104 | return result.result;
|
105 | }
|
106 | function getJsonResult(result) {
|
107 |
|
108 | if (result && result.status == 0 && result.message == "NOTOK" && (result.result || "").toLowerCase().indexOf("rate limit") >= 0) {
|
109 | var error = new Error("throttled response");
|
110 | error.result = JSON.stringify(result);
|
111 | error.throttleRetry = true;
|
112 | throw error;
|
113 | }
|
114 | if (result.jsonrpc != "2.0") {
|
115 |
|
116 | var error = new Error("invalid response");
|
117 | error.result = JSON.stringify(result);
|
118 | throw error;
|
119 | }
|
120 | if (result.error) {
|
121 |
|
122 | var error = new Error(result.error.message || "unknown error");
|
123 | if (result.error.code) {
|
124 | error.code = result.error.code;
|
125 | }
|
126 | if (result.error.data) {
|
127 | error.data = result.error.data;
|
128 | }
|
129 | throw error;
|
130 | }
|
131 | return result.result;
|
132 | }
|
133 |
|
134 | function checkLogTag(blockTag) {
|
135 | if (blockTag === "pending") {
|
136 | throw new Error("pending not supported");
|
137 | }
|
138 | if (blockTag === "latest") {
|
139 | return blockTag;
|
140 | }
|
141 | return parseInt(blockTag.substring(2), 16);
|
142 | }
|
143 | function checkError(method, error, transaction) {
|
144 |
|
145 |
|
146 | if (method === "call" && error.code === logger_1.Logger.errors.SERVER_ERROR) {
|
147 | var e = error.error;
|
148 |
|
149 | if (e && (e.message.match(/reverted/i) || e.message.match(/VM execution error/i))) {
|
150 |
|
151 | var data = e.data;
|
152 | if (data) {
|
153 | data = "0x" + data.replace(/^.*0x/i, "");
|
154 | }
|
155 | if ((0, bytes_1.isHexString)(data)) {
|
156 | return data;
|
157 | }
|
158 | logger.throwError("missing revert data in call exception", logger_1.Logger.errors.CALL_EXCEPTION, {
|
159 | error: error,
|
160 | data: "0x"
|
161 | });
|
162 | }
|
163 | }
|
164 |
|
165 | var message = error.message;
|
166 | if (error.code === logger_1.Logger.errors.SERVER_ERROR) {
|
167 | if (error.error && typeof (error.error.message) === "string") {
|
168 | message = error.error.message;
|
169 | }
|
170 | else if (typeof (error.body) === "string") {
|
171 | message = error.body;
|
172 | }
|
173 | else if (typeof (error.responseText) === "string") {
|
174 | message = error.responseText;
|
175 | }
|
176 | }
|
177 | message = (message || "").toLowerCase();
|
178 |
|
179 | if (message.match(/insufficient funds/)) {
|
180 | logger.throwError("insufficient funds for intrinsic transaction cost", logger_1.Logger.errors.INSUFFICIENT_FUNDS, {
|
181 | error: error,
|
182 | method: method,
|
183 | transaction: transaction
|
184 | });
|
185 | }
|
186 |
|
187 | if (message.match(/same hash was already imported|transaction nonce is too low|nonce too low/)) {
|
188 | logger.throwError("nonce has already been used", logger_1.Logger.errors.NONCE_EXPIRED, {
|
189 | error: error,
|
190 | method: method,
|
191 | transaction: transaction
|
192 | });
|
193 | }
|
194 |
|
195 | if (message.match(/another transaction with same nonce/)) {
|
196 | logger.throwError("replacement fee too low", logger_1.Logger.errors.REPLACEMENT_UNDERPRICED, {
|
197 | error: error,
|
198 | method: method,
|
199 | transaction: transaction
|
200 | });
|
201 | }
|
202 | if (message.match(/execution failed due to an exception|execution reverted/)) {
|
203 | logger.throwError("cannot estimate gas; transaction may fail or may require manual gas limit", logger_1.Logger.errors.UNPREDICTABLE_GAS_LIMIT, {
|
204 | error: error,
|
205 | method: method,
|
206 | transaction: transaction
|
207 | });
|
208 | }
|
209 | throw error;
|
210 | }
|
211 | var EtherscanProvider = (function (_super) {
|
212 | __extends(EtherscanProvider, _super);
|
213 | function EtherscanProvider(network, apiKey) {
|
214 | var _this = _super.call(this, network) || this;
|
215 | (0, properties_1.defineReadOnly)(_this, "baseUrl", _this.getBaseUrl());
|
216 | (0, properties_1.defineReadOnly)(_this, "apiKey", apiKey || null);
|
217 | return _this;
|
218 | }
|
219 | EtherscanProvider.prototype.getBaseUrl = function () {
|
220 | switch (this.network ? this.network.name : "invalid") {
|
221 | case "homestead":
|
222 | return "https:/\/api.etherscan.io";
|
223 | case "goerli":
|
224 | return "https:/\/api-goerli.etherscan.io";
|
225 | case "sepolia":
|
226 | return "https:/\/api-sepolia.etherscan.io";
|
227 | case "matic":
|
228 | return "https:/\/api.polygonscan.com";
|
229 | case "maticmum":
|
230 | return "https:/\/api-testnet.polygonscan.com";
|
231 | case "arbitrum":
|
232 | return "https:/\/api.arbiscan.io";
|
233 | case "arbitrum-goerli":
|
234 | return "https:/\/api-goerli.arbiscan.io";
|
235 | case "optimism":
|
236 | return "https:/\/api-optimistic.etherscan.io";
|
237 | case "optimism-goerli":
|
238 | return "https:/\/api-goerli-optimistic.etherscan.io";
|
239 | default:
|
240 | }
|
241 | return logger.throwArgumentError("unsupported network", "network", this.network.name);
|
242 | };
|
243 | EtherscanProvider.prototype.getUrl = function (module, params) {
|
244 | var query = Object.keys(params).reduce(function (accum, key) {
|
245 | var value = params[key];
|
246 | if (value != null) {
|
247 | accum += "&" + key + "=" + value;
|
248 | }
|
249 | return accum;
|
250 | }, "");
|
251 | var apiKey = ((this.apiKey) ? "&apikey=" + this.apiKey : "");
|
252 | return this.baseUrl + "/api?module=" + module + query + apiKey;
|
253 | };
|
254 | EtherscanProvider.prototype.getPostUrl = function () {
|
255 | return this.baseUrl + "/api";
|
256 | };
|
257 | EtherscanProvider.prototype.getPostData = function (module, params) {
|
258 | params.module = module;
|
259 | params.apikey = this.apiKey;
|
260 | return params;
|
261 | };
|
262 | EtherscanProvider.prototype.fetch = function (module, params, post) {
|
263 | return __awaiter(this, void 0, void 0, function () {
|
264 | var url, payload, procFunc, connection, payloadStr, result;
|
265 | var _this = this;
|
266 | return __generator(this, function (_a) {
|
267 | switch (_a.label) {
|
268 | case 0:
|
269 | url = (post ? this.getPostUrl() : this.getUrl(module, params));
|
270 | payload = (post ? this.getPostData(module, params) : null);
|
271 | procFunc = (module === "proxy") ? getJsonResult : getResult;
|
272 | this.emit("debug", {
|
273 | action: "request",
|
274 | request: url,
|
275 | provider: this
|
276 | });
|
277 | connection = {
|
278 | url: url,
|
279 | throttleSlotInterval: 1000,
|
280 | throttleCallback: function (attempt, url) {
|
281 | if (_this.isCommunityResource()) {
|
282 | (0, formatter_1.showThrottleMessage)();
|
283 | }
|
284 | return Promise.resolve(true);
|
285 | }
|
286 | };
|
287 | payloadStr = null;
|
288 | if (payload) {
|
289 | connection.headers = { "content-type": "application/x-www-form-urlencoded; charset=UTF-8" };
|
290 | payloadStr = Object.keys(payload).map(function (key) {
|
291 | return key + "=" + payload[key];
|
292 | }).join("&");
|
293 | }
|
294 | return [4 , (0, web_1.fetchJson)(connection, payloadStr, procFunc || getJsonResult)];
|
295 | case 1:
|
296 | result = _a.sent();
|
297 | this.emit("debug", {
|
298 | action: "response",
|
299 | request: url,
|
300 | response: (0, properties_1.deepCopy)(result),
|
301 | provider: this
|
302 | });
|
303 | return [2 , result];
|
304 | }
|
305 | });
|
306 | });
|
307 | };
|
308 | EtherscanProvider.prototype.detectNetwork = function () {
|
309 | return __awaiter(this, void 0, void 0, function () {
|
310 | return __generator(this, function (_a) {
|
311 | return [2 , this.network];
|
312 | });
|
313 | });
|
314 | };
|
315 | EtherscanProvider.prototype.perform = function (method, params) {
|
316 | return __awaiter(this, void 0, void 0, function () {
|
317 | var _a, postData, error_1, postData, error_2, args, topic0, logs, blocks, i, log, block, _b;
|
318 | return __generator(this, function (_c) {
|
319 | switch (_c.label) {
|
320 | case 0:
|
321 | _a = method;
|
322 | switch (_a) {
|
323 | case "getBlockNumber": return [3 , 1];
|
324 | case "getGasPrice": return [3 , 2];
|
325 | case "getBalance": return [3 , 3];
|
326 | case "getTransactionCount": return [3 , 4];
|
327 | case "getCode": return [3 , 5];
|
328 | case "getStorageAt": return [3 , 6];
|
329 | case "sendTransaction": return [3 , 7];
|
330 | case "getBlock": return [3 , 8];
|
331 | case "getTransaction": return [3 , 9];
|
332 | case "getTransactionReceipt": return [3 , 10];
|
333 | case "call": return [3 , 11];
|
334 | case "estimateGas": return [3 , 15];
|
335 | case "getLogs": return [3 , 19];
|
336 | case "getEtherPrice": return [3 , 26];
|
337 | }
|
338 | return [3 , 28];
|
339 | case 1: return [2 , this.fetch("proxy", { action: "eth_blockNumber" })];
|
340 | case 2: return [2 , this.fetch("proxy", { action: "eth_gasPrice" })];
|
341 | case 3:
|
342 |
|
343 | return [2 , this.fetch("account", {
|
344 | action: "balance",
|
345 | address: params.address,
|
346 | tag: params.blockTag
|
347 | })];
|
348 | case 4: return [2 , this.fetch("proxy", {
|
349 | action: "eth_getTransactionCount",
|
350 | address: params.address,
|
351 | tag: params.blockTag
|
352 | })];
|
353 | case 5: return [2 , this.fetch("proxy", {
|
354 | action: "eth_getCode",
|
355 | address: params.address,
|
356 | tag: params.blockTag
|
357 | })];
|
358 | case 6: return [2 , this.fetch("proxy", {
|
359 | action: "eth_getStorageAt",
|
360 | address: params.address,
|
361 | position: params.position,
|
362 | tag: params.blockTag
|
363 | })];
|
364 | case 7: return [2 , this.fetch("proxy", {
|
365 | action: "eth_sendRawTransaction",
|
366 | hex: params.signedTransaction
|
367 | }, true).catch(function (error) {
|
368 | return checkError("sendTransaction", error, params.signedTransaction);
|
369 | })];
|
370 | case 8:
|
371 | if (params.blockTag) {
|
372 | return [2 , this.fetch("proxy", {
|
373 | action: "eth_getBlockByNumber",
|
374 | tag: params.blockTag,
|
375 | boolean: (params.includeTransactions ? "true" : "false")
|
376 | })];
|
377 | }
|
378 | throw new Error("getBlock by blockHash not implemented");
|
379 | case 9: return [2 , this.fetch("proxy", {
|
380 | action: "eth_getTransactionByHash",
|
381 | txhash: params.transactionHash
|
382 | })];
|
383 | case 10: return [2 , this.fetch("proxy", {
|
384 | action: "eth_getTransactionReceipt",
|
385 | txhash: params.transactionHash
|
386 | })];
|
387 | case 11:
|
388 | if (params.blockTag !== "latest") {
|
389 | throw new Error("EtherscanProvider does not support blockTag for call");
|
390 | }
|
391 | postData = getTransactionPostData(params.transaction);
|
392 | postData.module = "proxy";
|
393 | postData.action = "eth_call";
|
394 | _c.label = 12;
|
395 | case 12:
|
396 | _c.trys.push([12, 14, , 15]);
|
397 | return [4 , this.fetch("proxy", postData, true)];
|
398 | case 13: return [2 , _c.sent()];
|
399 | case 14:
|
400 | error_1 = _c.sent();
|
401 | return [2 , checkError("call", error_1, params.transaction)];
|
402 | case 15:
|
403 | postData = getTransactionPostData(params.transaction);
|
404 | postData.module = "proxy";
|
405 | postData.action = "eth_estimateGas";
|
406 | _c.label = 16;
|
407 | case 16:
|
408 | _c.trys.push([16, 18, , 19]);
|
409 | return [4 , this.fetch("proxy", postData, true)];
|
410 | case 17: return [2 , _c.sent()];
|
411 | case 18:
|
412 | error_2 = _c.sent();
|
413 | return [2 , checkError("estimateGas", error_2, params.transaction)];
|
414 | case 19:
|
415 | args = { action: "getLogs" };
|
416 | if (params.filter.fromBlock) {
|
417 | args.fromBlock = checkLogTag(params.filter.fromBlock);
|
418 | }
|
419 | if (params.filter.toBlock) {
|
420 | args.toBlock = checkLogTag(params.filter.toBlock);
|
421 | }
|
422 | if (params.filter.address) {
|
423 | args.address = params.filter.address;
|
424 | }
|
425 |
|
426 | if (params.filter.topics && params.filter.topics.length > 0) {
|
427 | if (params.filter.topics.length > 1) {
|
428 | logger.throwError("unsupported topic count", logger_1.Logger.errors.UNSUPPORTED_OPERATION, { topics: params.filter.topics });
|
429 | }
|
430 | if (params.filter.topics.length === 1) {
|
431 | topic0 = params.filter.topics[0];
|
432 | if (typeof (topic0) !== "string" || topic0.length !== 66) {
|
433 | logger.throwError("unsupported topic format", logger_1.Logger.errors.UNSUPPORTED_OPERATION, { topic0: topic0 });
|
434 | }
|
435 | args.topic0 = topic0;
|
436 | }
|
437 | }
|
438 | return [4 , this.fetch("logs", args)];
|
439 | case 20:
|
440 | logs = _c.sent();
|
441 | blocks = {};
|
442 | i = 0;
|
443 | _c.label = 21;
|
444 | case 21:
|
445 | if (!(i < logs.length)) return [3 , 25];
|
446 | log = logs[i];
|
447 | if (log.blockHash != null) {
|
448 | return [3 , 24];
|
449 | }
|
450 | if (!(blocks[log.blockNumber] == null)) return [3 , 23];
|
451 | return [4 , this.getBlock(log.blockNumber)];
|
452 | case 22:
|
453 | block = _c.sent();
|
454 | if (block) {
|
455 | blocks[log.blockNumber] = block.hash;
|
456 | }
|
457 | _c.label = 23;
|
458 | case 23:
|
459 | log.blockHash = blocks[log.blockNumber];
|
460 | _c.label = 24;
|
461 | case 24:
|
462 | i++;
|
463 | return [3 , 21];
|
464 | case 25: return [2 , logs];
|
465 | case 26:
|
466 | if (this.network.name !== "homestead") {
|
467 | return [2 , 0.0];
|
468 | }
|
469 | _b = parseFloat;
|
470 | return [4 , this.fetch("stats", { action: "ethprice" })];
|
471 | case 27: return [2 , _b.apply(void 0, [(_c.sent()).ethusd])];
|
472 | case 28: return [3 , 29];
|
473 | case 29: return [2 , _super.prototype.perform.call(this, method, params)];
|
474 | }
|
475 | });
|
476 | });
|
477 | };
|
478 |
|
479 |
|
480 |
|
481 |
|
482 | EtherscanProvider.prototype.getHistory = function (addressOrName, startBlock, endBlock) {
|
483 | return __awaiter(this, void 0, void 0, function () {
|
484 | var params, result;
|
485 | var _a;
|
486 | var _this = this;
|
487 | return __generator(this, function (_b) {
|
488 | switch (_b.label) {
|
489 | case 0:
|
490 | _a = {
|
491 | action: "txlist"
|
492 | };
|
493 | return [4 , this.resolveName(addressOrName)];
|
494 | case 1:
|
495 | params = (_a.address = (_b.sent()),
|
496 | _a.startblock = ((startBlock == null) ? 0 : startBlock),
|
497 | _a.endblock = ((endBlock == null) ? 99999999 : endBlock),
|
498 | _a.sort = "asc",
|
499 | _a);
|
500 | return [4 , this.fetch("account", params)];
|
501 | case 2:
|
502 | result = _b.sent();
|
503 | return [2 , result.map(function (tx) {
|
504 | ["contractAddress", "to"].forEach(function (key) {
|
505 | if (tx[key] == "") {
|
506 | delete tx[key];
|
507 | }
|
508 | });
|
509 | if (tx.creates == null && tx.contractAddress != null) {
|
510 | tx.creates = tx.contractAddress;
|
511 | }
|
512 | var item = _this.formatter.transactionResponse(tx);
|
513 | if (tx.timeStamp) {
|
514 | item.timestamp = parseInt(tx.timeStamp);
|
515 | }
|
516 | return item;
|
517 | })];
|
518 | }
|
519 | });
|
520 | });
|
521 | };
|
522 | EtherscanProvider.prototype.isCommunityResource = function () {
|
523 | return (this.apiKey == null);
|
524 | };
|
525 | return EtherscanProvider;
|
526 | }(base_provider_1.BaseProvider));
|
527 | exports.EtherscanProvider = EtherscanProvider;
|
528 |
|
\ | No newline at end of file |