1 | "use strict";
|
2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
4 | return new (P || (P = Promise))(function (resolve, reject) {
|
5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
8 | step((generator = generator.apply(thisArg, _arguments || [])).next());
|
9 | });
|
10 | };
|
11 | import { Signer } from "@ethersproject/abstract-signer";
|
12 | import { BigNumber } from "@ethersproject/bignumber";
|
13 | import { hexlify, hexValue, hexZeroPad, isHexString } from "@ethersproject/bytes";
|
14 | import { _TypedDataEncoder } from "@ethersproject/hash";
|
15 | import { checkProperties, deepCopy, defineReadOnly, getStatic, resolveProperties, shallowCopy } from "@ethersproject/properties";
|
16 | import { toUtf8Bytes } from "@ethersproject/strings";
|
17 | import { accessListify } from "@ethersproject/transactions";
|
18 | import { fetchJson, poll } from "@ethersproject/web";
|
19 | import { Logger } from "@ethersproject/logger";
|
20 | import { version } from "./_version";
|
21 | const logger = new Logger(version);
|
22 | import { BaseProvider } from "./base-provider";
|
23 | const errorGas = ["call", "estimateGas"];
|
24 | function spelunk(value, requireData) {
|
25 | if (value == null) {
|
26 | return null;
|
27 | }
|
28 |
|
29 | if (typeof (value.message) === "string" && value.message.match("reverted")) {
|
30 | const data = isHexString(value.data) ? value.data : null;
|
31 | if (!requireData || data) {
|
32 | return { message: value.message, data };
|
33 | }
|
34 | }
|
35 |
|
36 | if (typeof (value) === "object") {
|
37 | for (const key in value) {
|
38 | const result = spelunk(value[key], requireData);
|
39 | if (result) {
|
40 | return result;
|
41 | }
|
42 | }
|
43 | return null;
|
44 | }
|
45 |
|
46 | if (typeof (value) === "string") {
|
47 | try {
|
48 | return spelunk(JSON.parse(value), requireData);
|
49 | }
|
50 | catch (error) { }
|
51 | }
|
52 | return null;
|
53 | }
|
54 | function checkError(method, error, params) {
|
55 | const transaction = params.transaction || params.signedTransaction;
|
56 |
|
57 |
|
58 | if (method === "call") {
|
59 | const result = spelunk(error, true);
|
60 | if (result) {
|
61 | return result.data;
|
62 | }
|
63 |
|
64 | logger.throwError("missing revert data in call exception; Transaction reverted without a reason string", Logger.errors.CALL_EXCEPTION, {
|
65 | data: "0x", transaction, error
|
66 | });
|
67 | }
|
68 | if (method === "estimateGas") {
|
69 |
|
70 | let result = spelunk(error.body, false);
|
71 | if (result == null) {
|
72 | result = spelunk(error, false);
|
73 | }
|
74 |
|
75 | if (result) {
|
76 | logger.throwError("cannot estimate gas; transaction may fail or may require manual gas limit", Logger.errors.UNPREDICTABLE_GAS_LIMIT, {
|
77 | reason: result.message, method, transaction, error
|
78 | });
|
79 | }
|
80 | }
|
81 |
|
82 | let message = error.message;
|
83 | if (error.code === Logger.errors.SERVER_ERROR && error.error && typeof (error.error.message) === "string") {
|
84 | message = error.error.message;
|
85 | }
|
86 | else if (typeof (error.body) === "string") {
|
87 | message = error.body;
|
88 | }
|
89 | else if (typeof (error.responseText) === "string") {
|
90 | message = error.responseText;
|
91 | }
|
92 | message = (message || "").toLowerCase();
|
93 |
|
94 | if (message.match(/insufficient funds|base fee exceeds gas limit/i)) {
|
95 | logger.throwError("insufficient funds for intrinsic transaction cost", Logger.errors.INSUFFICIENT_FUNDS, {
|
96 | error, method, transaction
|
97 | });
|
98 | }
|
99 |
|
100 | if (message.match(/nonce (is )?too low/i)) {
|
101 | logger.throwError("nonce has already been used", Logger.errors.NONCE_EXPIRED, {
|
102 | error, method, transaction
|
103 | });
|
104 | }
|
105 |
|
106 | if (message.match(/replacement transaction underpriced|transaction gas price.*too low/i)) {
|
107 | logger.throwError("replacement fee too low", Logger.errors.REPLACEMENT_UNDERPRICED, {
|
108 | error, method, transaction
|
109 | });
|
110 | }
|
111 |
|
112 | if (message.match(/only replay-protected/i)) {
|
113 | logger.throwError("legacy pre-eip-155 transactions not supported", Logger.errors.UNSUPPORTED_OPERATION, {
|
114 | error, method, transaction
|
115 | });
|
116 | }
|
117 | if (errorGas.indexOf(method) >= 0 && message.match(/gas required exceeds allowance|always failing transaction|execution reverted/)) {
|
118 | logger.throwError("cannot estimate gas; transaction may fail or may require manual gas limit", Logger.errors.UNPREDICTABLE_GAS_LIMIT, {
|
119 | error, method, transaction
|
120 | });
|
121 | }
|
122 | throw error;
|
123 | }
|
124 | function timer(timeout) {
|
125 | return new Promise(function (resolve) {
|
126 | setTimeout(resolve, timeout);
|
127 | });
|
128 | }
|
129 | function getResult(payload) {
|
130 | if (payload.error) {
|
131 |
|
132 | const error = new Error(payload.error.message);
|
133 | error.code = payload.error.code;
|
134 | error.data = payload.error.data;
|
135 | throw error;
|
136 | }
|
137 | return payload.result;
|
138 | }
|
139 | function getLowerCase(value) {
|
140 | if (value) {
|
141 | return value.toLowerCase();
|
142 | }
|
143 | return value;
|
144 | }
|
145 | const _constructorGuard = {};
|
146 | export class JsonRpcSigner extends Signer {
|
147 | constructor(constructorGuard, provider, addressOrIndex) {
|
148 | super();
|
149 | if (constructorGuard !== _constructorGuard) {
|
150 | throw new Error("do not call the JsonRpcSigner constructor directly; use provider.getSigner");
|
151 | }
|
152 | defineReadOnly(this, "provider", provider);
|
153 | if (addressOrIndex == null) {
|
154 | addressOrIndex = 0;
|
155 | }
|
156 | if (typeof (addressOrIndex) === "string") {
|
157 | defineReadOnly(this, "_address", this.provider.formatter.address(addressOrIndex));
|
158 | defineReadOnly(this, "_index", null);
|
159 | }
|
160 | else if (typeof (addressOrIndex) === "number") {
|
161 | defineReadOnly(this, "_index", addressOrIndex);
|
162 | defineReadOnly(this, "_address", null);
|
163 | }
|
164 | else {
|
165 | logger.throwArgumentError("invalid address or index", "addressOrIndex", addressOrIndex);
|
166 | }
|
167 | }
|
168 | connect(provider) {
|
169 | return logger.throwError("cannot alter JSON-RPC Signer connection", Logger.errors.UNSUPPORTED_OPERATION, {
|
170 | operation: "connect"
|
171 | });
|
172 | }
|
173 | connectUnchecked() {
|
174 | return new UncheckedJsonRpcSigner(_constructorGuard, this.provider, this._address || this._index);
|
175 | }
|
176 | getAddress() {
|
177 | if (this._address) {
|
178 | return Promise.resolve(this._address);
|
179 | }
|
180 | return this.provider.send("eth_accounts", []).then((accounts) => {
|
181 | if (accounts.length <= this._index) {
|
182 | logger.throwError("unknown account #" + this._index, Logger.errors.UNSUPPORTED_OPERATION, {
|
183 | operation: "getAddress"
|
184 | });
|
185 | }
|
186 | return this.provider.formatter.address(accounts[this._index]);
|
187 | });
|
188 | }
|
189 | sendUncheckedTransaction(transaction) {
|
190 | transaction = shallowCopy(transaction);
|
191 | const fromAddress = this.getAddress().then((address) => {
|
192 | if (address) {
|
193 | address = address.toLowerCase();
|
194 | }
|
195 | return address;
|
196 | });
|
197 |
|
198 |
|
199 |
|
200 | if (transaction.gasLimit == null) {
|
201 | const estimate = shallowCopy(transaction);
|
202 | estimate.from = fromAddress;
|
203 | transaction.gasLimit = this.provider.estimateGas(estimate);
|
204 | }
|
205 | if (transaction.to != null) {
|
206 | transaction.to = Promise.resolve(transaction.to).then((to) => __awaiter(this, void 0, void 0, function* () {
|
207 | if (to == null) {
|
208 | return null;
|
209 | }
|
210 | const address = yield this.provider.resolveName(to);
|
211 | if (address == null) {
|
212 | logger.throwArgumentError("provided ENS name resolves to null", "tx.to", to);
|
213 | }
|
214 | return address;
|
215 | }));
|
216 | }
|
217 | return resolveProperties({
|
218 | tx: resolveProperties(transaction),
|
219 | sender: fromAddress
|
220 | }).then(({ tx, sender }) => {
|
221 | if (tx.from != null) {
|
222 | if (tx.from.toLowerCase() !== sender) {
|
223 | logger.throwArgumentError("from address mismatch", "transaction", transaction);
|
224 | }
|
225 | }
|
226 | else {
|
227 | tx.from = sender;
|
228 | }
|
229 | const hexTx = this.provider.constructor.hexlifyTransaction(tx, { from: true });
|
230 | return this.provider.send("eth_sendTransaction", [hexTx]).then((hash) => {
|
231 | return hash;
|
232 | }, (error) => {
|
233 | return checkError("sendTransaction", error, hexTx);
|
234 | });
|
235 | });
|
236 | }
|
237 | signTransaction(transaction) {
|
238 | return logger.throwError("signing transactions is unsupported", Logger.errors.UNSUPPORTED_OPERATION, {
|
239 | operation: "signTransaction"
|
240 | });
|
241 | }
|
242 | sendTransaction(transaction) {
|
243 | return __awaiter(this, void 0, void 0, function* () {
|
244 |
|
245 | const blockNumber = yield this.provider._getInternalBlockNumber(100 + 2 * this.provider.pollingInterval);
|
246 |
|
247 | const hash = yield this.sendUncheckedTransaction(transaction);
|
248 | try {
|
249 |
|
250 |
|
251 |
|
252 | return yield poll(() => __awaiter(this, void 0, void 0, function* () {
|
253 | const tx = yield this.provider.getTransaction(hash);
|
254 | if (tx === null) {
|
255 | return undefined;
|
256 | }
|
257 | return this.provider._wrapTransaction(tx, hash, blockNumber);
|
258 | }), { oncePoll: this.provider });
|
259 | }
|
260 | catch (error) {
|
261 | error.transactionHash = hash;
|
262 | throw error;
|
263 | }
|
264 | });
|
265 | }
|
266 | signMessage(message) {
|
267 | return __awaiter(this, void 0, void 0, function* () {
|
268 | const data = ((typeof (message) === "string") ? toUtf8Bytes(message) : message);
|
269 | const address = yield this.getAddress();
|
270 | return yield this.provider.send("personal_sign", [hexlify(data), address.toLowerCase()]);
|
271 | });
|
272 | }
|
273 | _legacySignMessage(message) {
|
274 | return __awaiter(this, void 0, void 0, function* () {
|
275 | const data = ((typeof (message) === "string") ? toUtf8Bytes(message) : message);
|
276 | const address = yield this.getAddress();
|
277 |
|
278 | return yield this.provider.send("eth_sign", [address.toLowerCase(), hexlify(data)]);
|
279 | });
|
280 | }
|
281 | _signTypedData(domain, types, value) {
|
282 | return __awaiter(this, void 0, void 0, function* () {
|
283 |
|
284 | const populated = yield _TypedDataEncoder.resolveNames(domain, types, value, (name) => {
|
285 | return this.provider.resolveName(name);
|
286 | });
|
287 | const address = yield this.getAddress();
|
288 | return yield this.provider.send("eth_signTypedData_v4", [
|
289 | address.toLowerCase(),
|
290 | JSON.stringify(_TypedDataEncoder.getPayload(populated.domain, types, populated.value))
|
291 | ]);
|
292 | });
|
293 | }
|
294 | unlock(password) {
|
295 | return __awaiter(this, void 0, void 0, function* () {
|
296 | const provider = this.provider;
|
297 | const address = yield this.getAddress();
|
298 | return provider.send("personal_unlockAccount", [address.toLowerCase(), password, null]);
|
299 | });
|
300 | }
|
301 | }
|
302 | class UncheckedJsonRpcSigner extends JsonRpcSigner {
|
303 | sendTransaction(transaction) {
|
304 | return this.sendUncheckedTransaction(transaction).then((hash) => {
|
305 | return {
|
306 | hash: hash,
|
307 | nonce: null,
|
308 | gasLimit: null,
|
309 | gasPrice: null,
|
310 | data: null,
|
311 | value: null,
|
312 | chainId: null,
|
313 | confirmations: 0,
|
314 | from: null,
|
315 | wait: (confirmations) => { return this.provider.waitForTransaction(hash, confirmations); }
|
316 | };
|
317 | });
|
318 | }
|
319 | }
|
320 | const allowedTransactionKeys = {
|
321 | chainId: true, data: true, gasLimit: true, gasPrice: true, nonce: true, to: true, value: true,
|
322 | type: true, accessList: true,
|
323 | maxFeePerGas: true, maxPriorityFeePerGas: true
|
324 | };
|
325 | export class JsonRpcProvider extends BaseProvider {
|
326 | constructor(url, network) {
|
327 | let networkOrReady = network;
|
328 |
|
329 | if (networkOrReady == null) {
|
330 | networkOrReady = new Promise((resolve, reject) => {
|
331 | setTimeout(() => {
|
332 | this.detectNetwork().then((network) => {
|
333 | resolve(network);
|
334 | }, (error) => {
|
335 | reject(error);
|
336 | });
|
337 | }, 0);
|
338 | });
|
339 | }
|
340 | super(networkOrReady);
|
341 |
|
342 | if (!url) {
|
343 | url = getStatic(this.constructor, "defaultUrl")();
|
344 | }
|
345 | if (typeof (url) === "string") {
|
346 | defineReadOnly(this, "connection", Object.freeze({
|
347 | url: url
|
348 | }));
|
349 | }
|
350 | else {
|
351 | defineReadOnly(this, "connection", Object.freeze(shallowCopy(url)));
|
352 | }
|
353 | this._nextId = 42;
|
354 | }
|
355 | get _cache() {
|
356 | if (this._eventLoopCache == null) {
|
357 | this._eventLoopCache = {};
|
358 | }
|
359 | return this._eventLoopCache;
|
360 | }
|
361 | static defaultUrl() {
|
362 | return "http:/\/localhost:8545";
|
363 | }
|
364 | detectNetwork() {
|
365 | if (!this._cache["detectNetwork"]) {
|
366 | this._cache["detectNetwork"] = this._uncachedDetectNetwork();
|
367 |
|
368 | setTimeout(() => {
|
369 | this._cache["detectNetwork"] = null;
|
370 | }, 0);
|
371 | }
|
372 | return this._cache["detectNetwork"];
|
373 | }
|
374 | _uncachedDetectNetwork() {
|
375 | return __awaiter(this, void 0, void 0, function* () {
|
376 | yield timer(0);
|
377 | let chainId = null;
|
378 | try {
|
379 | chainId = yield this.send("eth_chainId", []);
|
380 | }
|
381 | catch (error) {
|
382 | try {
|
383 | chainId = yield this.send("net_version", []);
|
384 | }
|
385 | catch (error) { }
|
386 | }
|
387 | if (chainId != null) {
|
388 | const getNetwork = getStatic(this.constructor, "getNetwork");
|
389 | try {
|
390 | return getNetwork(BigNumber.from(chainId).toNumber());
|
391 | }
|
392 | catch (error) {
|
393 | return logger.throwError("could not detect network", Logger.errors.NETWORK_ERROR, {
|
394 | chainId: chainId,
|
395 | event: "invalidNetwork",
|
396 | serverError: error
|
397 | });
|
398 | }
|
399 | }
|
400 | return logger.throwError("could not detect network", Logger.errors.NETWORK_ERROR, {
|
401 | event: "noNetwork"
|
402 | });
|
403 | });
|
404 | }
|
405 | getSigner(addressOrIndex) {
|
406 | return new JsonRpcSigner(_constructorGuard, this, addressOrIndex);
|
407 | }
|
408 | getUncheckedSigner(addressOrIndex) {
|
409 | return this.getSigner(addressOrIndex).connectUnchecked();
|
410 | }
|
411 | listAccounts() {
|
412 | return this.send("eth_accounts", []).then((accounts) => {
|
413 | return accounts.map((a) => this.formatter.address(a));
|
414 | });
|
415 | }
|
416 | send(method, params) {
|
417 | const request = {
|
418 | method: method,
|
419 | params: params,
|
420 | id: (this._nextId++),
|
421 | jsonrpc: "2.0"
|
422 | };
|
423 | this.emit("debug", {
|
424 | action: "request",
|
425 | request: deepCopy(request),
|
426 | provider: this
|
427 | });
|
428 |
|
429 |
|
430 | const cache = (["eth_chainId", "eth_blockNumber"].indexOf(method) >= 0);
|
431 | if (cache && this._cache[method]) {
|
432 | return this._cache[method];
|
433 | }
|
434 | const result = fetchJson(this.connection, JSON.stringify(request), getResult).then((result) => {
|
435 | this.emit("debug", {
|
436 | action: "response",
|
437 | request: request,
|
438 | response: result,
|
439 | provider: this
|
440 | });
|
441 | return result;
|
442 | }, (error) => {
|
443 | this.emit("debug", {
|
444 | action: "response",
|
445 | error: error,
|
446 | request: request,
|
447 | provider: this
|
448 | });
|
449 | throw error;
|
450 | });
|
451 |
|
452 | if (cache) {
|
453 | this._cache[method] = result;
|
454 | setTimeout(() => {
|
455 | this._cache[method] = null;
|
456 | }, 0);
|
457 | }
|
458 | return result;
|
459 | }
|
460 | prepareRequest(method, params) {
|
461 | switch (method) {
|
462 | case "getBlockNumber":
|
463 | return ["eth_blockNumber", []];
|
464 | case "getGasPrice":
|
465 | return ["eth_gasPrice", []];
|
466 | case "getBalance":
|
467 | return ["eth_getBalance", [getLowerCase(params.address), params.blockTag]];
|
468 | case "getTransactionCount":
|
469 | return ["eth_getTransactionCount", [getLowerCase(params.address), params.blockTag]];
|
470 | case "getCode":
|
471 | return ["eth_getCode", [getLowerCase(params.address), params.blockTag]];
|
472 | case "getStorageAt":
|
473 | return ["eth_getStorageAt", [getLowerCase(params.address), hexZeroPad(params.position, 32), params.blockTag]];
|
474 | case "sendTransaction":
|
475 | return ["eth_sendRawTransaction", [params.signedTransaction]];
|
476 | case "getBlock":
|
477 | if (params.blockTag) {
|
478 | return ["eth_getBlockByNumber", [params.blockTag, !!params.includeTransactions]];
|
479 | }
|
480 | else if (params.blockHash) {
|
481 | return ["eth_getBlockByHash", [params.blockHash, !!params.includeTransactions]];
|
482 | }
|
483 | return null;
|
484 | case "getTransaction":
|
485 | return ["eth_getTransactionByHash", [params.transactionHash]];
|
486 | case "getTransactionReceipt":
|
487 | return ["eth_getTransactionReceipt", [params.transactionHash]];
|
488 | case "call": {
|
489 | const hexlifyTransaction = getStatic(this.constructor, "hexlifyTransaction");
|
490 | return ["eth_call", [hexlifyTransaction(params.transaction, { from: true }), params.blockTag]];
|
491 | }
|
492 | case "estimateGas": {
|
493 | const hexlifyTransaction = getStatic(this.constructor, "hexlifyTransaction");
|
494 | return ["eth_estimateGas", [hexlifyTransaction(params.transaction, { from: true })]];
|
495 | }
|
496 | case "getLogs":
|
497 | if (params.filter && params.filter.address != null) {
|
498 | params.filter.address = getLowerCase(params.filter.address);
|
499 | }
|
500 | return ["eth_getLogs", [params.filter]];
|
501 | default:
|
502 | break;
|
503 | }
|
504 | return null;
|
505 | }
|
506 | perform(method, params) {
|
507 | return __awaiter(this, void 0, void 0, function* () {
|
508 |
|
509 |
|
510 | if (method === "call" || method === "estimateGas") {
|
511 | const tx = params.transaction;
|
512 | if (tx && tx.type != null && BigNumber.from(tx.type).isZero()) {
|
513 |
|
514 | if (tx.maxFeePerGas == null && tx.maxPriorityFeePerGas == null) {
|
515 | const feeData = yield this.getFeeData();
|
516 | if (feeData.maxFeePerGas == null && feeData.maxPriorityFeePerGas == null) {
|
517 |
|
518 | params = shallowCopy(params);
|
519 | params.transaction = shallowCopy(tx);
|
520 | delete params.transaction.type;
|
521 | }
|
522 | }
|
523 | }
|
524 | }
|
525 | const args = this.prepareRequest(method, params);
|
526 | if (args == null) {
|
527 | logger.throwError(method + " not implemented", Logger.errors.NOT_IMPLEMENTED, { operation: method });
|
528 | }
|
529 | try {
|
530 | return yield this.send(args[0], args[1]);
|
531 | }
|
532 | catch (error) {
|
533 | return checkError(method, error, params);
|
534 | }
|
535 | });
|
536 | }
|
537 | _startEvent(event) {
|
538 | if (event.tag === "pending") {
|
539 | this._startPending();
|
540 | }
|
541 | super._startEvent(event);
|
542 | }
|
543 | _startPending() {
|
544 | if (this._pendingFilter != null) {
|
545 | return;
|
546 | }
|
547 | const self = this;
|
548 | const pendingFilter = this.send("eth_newPendingTransactionFilter", []);
|
549 | this._pendingFilter = pendingFilter;
|
550 | pendingFilter.then(function (filterId) {
|
551 | function poll() {
|
552 | self.send("eth_getFilterChanges", [filterId]).then(function (hashes) {
|
553 | if (self._pendingFilter != pendingFilter) {
|
554 | return null;
|
555 | }
|
556 | let seq = Promise.resolve();
|
557 | hashes.forEach(function (hash) {
|
558 |
|
559 | self._emitted["t:" + hash.toLowerCase()] = "pending";
|
560 | seq = seq.then(function () {
|
561 | return self.getTransaction(hash).then(function (tx) {
|
562 | self.emit("pending", tx);
|
563 | return null;
|
564 | });
|
565 | });
|
566 | });
|
567 | return seq.then(function () {
|
568 | return timer(1000);
|
569 | });
|
570 | }).then(function () {
|
571 | if (self._pendingFilter != pendingFilter) {
|
572 | self.send("eth_uninstallFilter", [filterId]);
|
573 | return;
|
574 | }
|
575 | setTimeout(function () { poll(); }, 0);
|
576 | return null;
|
577 | }).catch((error) => { });
|
578 | }
|
579 | poll();
|
580 | return filterId;
|
581 | }).catch((error) => { });
|
582 | }
|
583 | _stopEvent(event) {
|
584 | if (event.tag === "pending" && this.listenerCount("pending") === 0) {
|
585 | this._pendingFilter = null;
|
586 | }
|
587 | super._stopEvent(event);
|
588 | }
|
589 |
|
590 |
|
591 |
|
592 |
|
593 |
|
594 |
|
595 |
|
596 |
|
597 |
|
598 | static hexlifyTransaction(transaction, allowExtra) {
|
599 |
|
600 | const allowed = shallowCopy(allowedTransactionKeys);
|
601 | if (allowExtra) {
|
602 | for (const key in allowExtra) {
|
603 | if (allowExtra[key]) {
|
604 | allowed[key] = true;
|
605 | }
|
606 | }
|
607 | }
|
608 | checkProperties(transaction, allowed);
|
609 | const result = {};
|
610 |
|
611 | ["chainId", "gasLimit", "gasPrice", "type", "maxFeePerGas", "maxPriorityFeePerGas", "nonce", "value"].forEach(function (key) {
|
612 | if (transaction[key] == null) {
|
613 | return;
|
614 | }
|
615 | const value = hexValue(BigNumber.from(transaction[key]));
|
616 | if (key === "gasLimit") {
|
617 | key = "gas";
|
618 | }
|
619 | result[key] = value;
|
620 | });
|
621 | ["from", "to", "data"].forEach(function (key) {
|
622 | if (transaction[key] == null) {
|
623 | return;
|
624 | }
|
625 | result[key] = hexlify(transaction[key]);
|
626 | });
|
627 | if (transaction.accessList) {
|
628 | result["accessList"] = accessListify(transaction.accessList);
|
629 | }
|
630 | return result;
|
631 | }
|
632 | }
|
633 |
|
\ | No newline at end of file |