UNPKG

18.4 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.showThrottleMessage = exports.isCommunityResource = exports.isCommunityResourcable = exports.Formatter = void 0;
4var address_1 = require("@ethersproject/address");
5var bignumber_1 = require("@ethersproject/bignumber");
6var bytes_1 = require("@ethersproject/bytes");
7var constants_1 = require("@ethersproject/constants");
8var properties_1 = require("@ethersproject/properties");
9var transactions_1 = require("@ethersproject/transactions");
10var logger_1 = require("@ethersproject/logger");
11var _version_1 = require("./_version");
12var logger = new logger_1.Logger(_version_1.version);
13var Formatter = /** @class */ (function () {
14 function Formatter() {
15 this.formats = this.getDefaultFormats();
16 }
17 Formatter.prototype.getDefaultFormats = function () {
18 var _this = this;
19 var formats = ({});
20 var address = this.address.bind(this);
21 var bigNumber = this.bigNumber.bind(this);
22 var blockTag = this.blockTag.bind(this);
23 var data = this.data.bind(this);
24 var hash = this.hash.bind(this);
25 var hex = this.hex.bind(this);
26 var number = this.number.bind(this);
27 var type = this.type.bind(this);
28 var strictData = function (v) { return _this.data(v, true); };
29 formats.transaction = {
30 hash: hash,
31 type: type,
32 accessList: Formatter.allowNull(this.accessList.bind(this), null),
33 blockHash: Formatter.allowNull(hash, null),
34 blockNumber: Formatter.allowNull(number, null),
35 transactionIndex: Formatter.allowNull(number, null),
36 confirmations: Formatter.allowNull(number, null),
37 from: address,
38 // either (gasPrice) or (maxPriorityFeePerGas + maxFeePerGas)
39 // must be set
40 gasPrice: Formatter.allowNull(bigNumber),
41 maxPriorityFeePerGas: Formatter.allowNull(bigNumber),
42 maxFeePerGas: Formatter.allowNull(bigNumber),
43 gasLimit: bigNumber,
44 to: Formatter.allowNull(address, null),
45 value: bigNumber,
46 nonce: number,
47 data: data,
48 r: Formatter.allowNull(this.uint256),
49 s: Formatter.allowNull(this.uint256),
50 v: Formatter.allowNull(number),
51 creates: Formatter.allowNull(address, null),
52 raw: Formatter.allowNull(data),
53 };
54 formats.transactionRequest = {
55 from: Formatter.allowNull(address),
56 nonce: Formatter.allowNull(number),
57 gasLimit: Formatter.allowNull(bigNumber),
58 gasPrice: Formatter.allowNull(bigNumber),
59 maxPriorityFeePerGas: Formatter.allowNull(bigNumber),
60 maxFeePerGas: Formatter.allowNull(bigNumber),
61 to: Formatter.allowNull(address),
62 value: Formatter.allowNull(bigNumber),
63 data: Formatter.allowNull(strictData),
64 type: Formatter.allowNull(number),
65 accessList: Formatter.allowNull(this.accessList.bind(this), null),
66 };
67 formats.receiptLog = {
68 transactionIndex: number,
69 blockNumber: number,
70 transactionHash: hash,
71 address: address,
72 topics: Formatter.arrayOf(hash),
73 data: data,
74 logIndex: number,
75 blockHash: hash,
76 };
77 formats.receipt = {
78 to: Formatter.allowNull(this.address, null),
79 from: Formatter.allowNull(this.address, null),
80 contractAddress: Formatter.allowNull(address, null),
81 transactionIndex: number,
82 // should be allowNull(hash), but broken-EIP-658 support is handled in receipt
83 root: Formatter.allowNull(hex),
84 gasUsed: bigNumber,
85 logsBloom: Formatter.allowNull(data),
86 blockHash: hash,
87 transactionHash: hash,
88 logs: Formatter.arrayOf(this.receiptLog.bind(this)),
89 blockNumber: number,
90 confirmations: Formatter.allowNull(number, null),
91 cumulativeGasUsed: bigNumber,
92 effectiveGasPrice: Formatter.allowNull(bigNumber),
93 status: Formatter.allowNull(number),
94 type: type
95 };
96 formats.block = {
97 hash: Formatter.allowNull(hash),
98 parentHash: hash,
99 number: number,
100 timestamp: number,
101 nonce: Formatter.allowNull(hex),
102 difficulty: this.difficulty.bind(this),
103 gasLimit: bigNumber,
104 gasUsed: bigNumber,
105 miner: Formatter.allowNull(address),
106 extraData: data,
107 transactions: Formatter.allowNull(Formatter.arrayOf(hash)),
108 baseFeePerGas: Formatter.allowNull(bigNumber)
109 };
110 formats.blockWithTransactions = (0, properties_1.shallowCopy)(formats.block);
111 formats.blockWithTransactions.transactions = Formatter.allowNull(Formatter.arrayOf(this.transactionResponse.bind(this)));
112 formats.filter = {
113 fromBlock: Formatter.allowNull(blockTag, undefined),
114 toBlock: Formatter.allowNull(blockTag, undefined),
115 blockHash: Formatter.allowNull(hash, undefined),
116 address: Formatter.allowNull(address, undefined),
117 topics: Formatter.allowNull(this.topics.bind(this), undefined),
118 };
119 formats.filterLog = {
120 blockNumber: Formatter.allowNull(number),
121 blockHash: Formatter.allowNull(hash),
122 transactionIndex: number,
123 removed: Formatter.allowNull(this.boolean.bind(this)),
124 address: address,
125 data: Formatter.allowFalsish(data, "0x"),
126 topics: Formatter.arrayOf(hash),
127 transactionHash: hash,
128 logIndex: number,
129 };
130 return formats;
131 };
132 Formatter.prototype.accessList = function (accessList) {
133 return (0, transactions_1.accessListify)(accessList || []);
134 };
135 // Requires a BigNumberish that is within the IEEE754 safe integer range; returns a number
136 // Strict! Used on input.
137 Formatter.prototype.number = function (number) {
138 if (number === "0x") {
139 return 0;
140 }
141 return bignumber_1.BigNumber.from(number).toNumber();
142 };
143 Formatter.prototype.type = function (number) {
144 if (number === "0x" || number == null) {
145 return 0;
146 }
147 return bignumber_1.BigNumber.from(number).toNumber();
148 };
149 // Strict! Used on input.
150 Formatter.prototype.bigNumber = function (value) {
151 return bignumber_1.BigNumber.from(value);
152 };
153 // Requires a boolean, "true" or "false"; returns a boolean
154 Formatter.prototype.boolean = function (value) {
155 if (typeof (value) === "boolean") {
156 return value;
157 }
158 if (typeof (value) === "string") {
159 value = value.toLowerCase();
160 if (value === "true") {
161 return true;
162 }
163 if (value === "false") {
164 return false;
165 }
166 }
167 throw new Error("invalid boolean - " + value);
168 };
169 Formatter.prototype.hex = function (value, strict) {
170 if (typeof (value) === "string") {
171 if (!strict && value.substring(0, 2) !== "0x") {
172 value = "0x" + value;
173 }
174 if ((0, bytes_1.isHexString)(value)) {
175 return value.toLowerCase();
176 }
177 }
178 return logger.throwArgumentError("invalid hash", "value", value);
179 };
180 Formatter.prototype.data = function (value, strict) {
181 var result = this.hex(value, strict);
182 if ((result.length % 2) !== 0) {
183 throw new Error("invalid data; odd-length - " + value);
184 }
185 return result;
186 };
187 // Requires an address
188 // Strict! Used on input.
189 Formatter.prototype.address = function (value) {
190 return (0, address_1.getAddress)(value);
191 };
192 Formatter.prototype.callAddress = function (value) {
193 if (!(0, bytes_1.isHexString)(value, 32)) {
194 return null;
195 }
196 var address = (0, address_1.getAddress)((0, bytes_1.hexDataSlice)(value, 12));
197 return (address === constants_1.AddressZero) ? null : address;
198 };
199 Formatter.prototype.contractAddress = function (value) {
200 return (0, address_1.getContractAddress)(value);
201 };
202 // Strict! Used on input.
203 Formatter.prototype.blockTag = function (blockTag) {
204 if (blockTag == null) {
205 return "latest";
206 }
207 if (blockTag === "earliest") {
208 return "0x0";
209 }
210 if (blockTag === "latest" || blockTag === "pending") {
211 return blockTag;
212 }
213 if (typeof (blockTag) === "number" || (0, bytes_1.isHexString)(blockTag)) {
214 return (0, bytes_1.hexValue)(blockTag);
215 }
216 throw new Error("invalid blockTag");
217 };
218 // Requires a hash, optionally requires 0x prefix; returns prefixed lowercase hash.
219 Formatter.prototype.hash = function (value, strict) {
220 var result = this.hex(value, strict);
221 if ((0, bytes_1.hexDataLength)(result) !== 32) {
222 return logger.throwArgumentError("invalid hash", "value", value);
223 }
224 return result;
225 };
226 // Returns the difficulty as a number, or if too large (i.e. PoA network) null
227 Formatter.prototype.difficulty = function (value) {
228 if (value == null) {
229 return null;
230 }
231 var v = bignumber_1.BigNumber.from(value);
232 try {
233 return v.toNumber();
234 }
235 catch (error) { }
236 return null;
237 };
238 Formatter.prototype.uint256 = function (value) {
239 if (!(0, bytes_1.isHexString)(value)) {
240 throw new Error("invalid uint256");
241 }
242 return (0, bytes_1.hexZeroPad)(value, 32);
243 };
244 Formatter.prototype._block = function (value, format) {
245 if (value.author != null && value.miner == null) {
246 value.miner = value.author;
247 }
248 // The difficulty may need to come from _difficulty in recursed blocks
249 var difficulty = (value._difficulty != null) ? value._difficulty : value.difficulty;
250 var result = Formatter.check(format, value);
251 result._difficulty = ((difficulty == null) ? null : bignumber_1.BigNumber.from(difficulty));
252 return result;
253 };
254 Formatter.prototype.block = function (value) {
255 return this._block(value, this.formats.block);
256 };
257 Formatter.prototype.blockWithTransactions = function (value) {
258 return this._block(value, this.formats.blockWithTransactions);
259 };
260 // Strict! Used on input.
261 Formatter.prototype.transactionRequest = function (value) {
262 return Formatter.check(this.formats.transactionRequest, value);
263 };
264 Formatter.prototype.transactionResponse = function (transaction) {
265 // Rename gas to gasLimit
266 if (transaction.gas != null && transaction.gasLimit == null) {
267 transaction.gasLimit = transaction.gas;
268 }
269 // Some clients (TestRPC) do strange things like return 0x0 for the
270 // 0 address; correct this to be a real address
271 if (transaction.to && bignumber_1.BigNumber.from(transaction.to).isZero()) {
272 transaction.to = "0x0000000000000000000000000000000000000000";
273 }
274 // Rename input to data
275 if (transaction.input != null && transaction.data == null) {
276 transaction.data = transaction.input;
277 }
278 // If to and creates are empty, populate the creates from the transaction
279 if (transaction.to == null && transaction.creates == null) {
280 transaction.creates = this.contractAddress(transaction);
281 }
282 if ((transaction.type === 1 || transaction.type === 2) && transaction.accessList == null) {
283 transaction.accessList = [];
284 }
285 var result = Formatter.check(this.formats.transaction, transaction);
286 if (transaction.chainId != null) {
287 var chainId = transaction.chainId;
288 if ((0, bytes_1.isHexString)(chainId)) {
289 chainId = bignumber_1.BigNumber.from(chainId).toNumber();
290 }
291 result.chainId = chainId;
292 }
293 else {
294 var chainId = transaction.networkId;
295 // geth-etc returns chainId
296 if (chainId == null && result.v == null) {
297 chainId = transaction.chainId;
298 }
299 if ((0, bytes_1.isHexString)(chainId)) {
300 chainId = bignumber_1.BigNumber.from(chainId).toNumber();
301 }
302 if (typeof (chainId) !== "number" && result.v != null) {
303 chainId = (result.v - 35) / 2;
304 if (chainId < 0) {
305 chainId = 0;
306 }
307 chainId = parseInt(chainId);
308 }
309 if (typeof (chainId) !== "number") {
310 chainId = 0;
311 }
312 result.chainId = chainId;
313 }
314 // 0x0000... should actually be null
315 if (result.blockHash && result.blockHash.replace(/0/g, "") === "x") {
316 result.blockHash = null;
317 }
318 return result;
319 };
320 Formatter.prototype.transaction = function (value) {
321 return (0, transactions_1.parse)(value);
322 };
323 Formatter.prototype.receiptLog = function (value) {
324 return Formatter.check(this.formats.receiptLog, value);
325 };
326 Formatter.prototype.receipt = function (value) {
327 var result = Formatter.check(this.formats.receipt, value);
328 // RSK incorrectly implemented EIP-658, so we munge things a bit here for it
329 if (result.root != null) {
330 if (result.root.length <= 4) {
331 // Could be 0x00, 0x0, 0x01 or 0x1
332 var value_1 = bignumber_1.BigNumber.from(result.root).toNumber();
333 if (value_1 === 0 || value_1 === 1) {
334 // Make sure if both are specified, they match
335 if (result.status != null && (result.status !== value_1)) {
336 logger.throwArgumentError("alt-root-status/status mismatch", "value", { root: result.root, status: result.status });
337 }
338 result.status = value_1;
339 delete result.root;
340 }
341 else {
342 logger.throwArgumentError("invalid alt-root-status", "value.root", result.root);
343 }
344 }
345 else if (result.root.length !== 66) {
346 // Must be a valid bytes32
347 logger.throwArgumentError("invalid root hash", "value.root", result.root);
348 }
349 }
350 if (result.status != null) {
351 result.byzantium = true;
352 }
353 return result;
354 };
355 Formatter.prototype.topics = function (value) {
356 var _this = this;
357 if (Array.isArray(value)) {
358 return value.map(function (v) { return _this.topics(v); });
359 }
360 else if (value != null) {
361 return this.hash(value, true);
362 }
363 return null;
364 };
365 Formatter.prototype.filter = function (value) {
366 return Formatter.check(this.formats.filter, value);
367 };
368 Formatter.prototype.filterLog = function (value) {
369 return Formatter.check(this.formats.filterLog, value);
370 };
371 Formatter.check = function (format, object) {
372 var result = {};
373 for (var key in format) {
374 try {
375 var value = format[key](object[key]);
376 if (value !== undefined) {
377 result[key] = value;
378 }
379 }
380 catch (error) {
381 error.checkKey = key;
382 error.checkValue = object[key];
383 throw error;
384 }
385 }
386 return result;
387 };
388 // if value is null-ish, nullValue is returned
389 Formatter.allowNull = function (format, nullValue) {
390 return (function (value) {
391 if (value == null) {
392 return nullValue;
393 }
394 return format(value);
395 });
396 };
397 // If value is false-ish, replaceValue is returned
398 Formatter.allowFalsish = function (format, replaceValue) {
399 return (function (value) {
400 if (!value) {
401 return replaceValue;
402 }
403 return format(value);
404 });
405 };
406 // Requires an Array satisfying check
407 Formatter.arrayOf = function (format) {
408 return (function (array) {
409 if (!Array.isArray(array)) {
410 throw new Error("not an array");
411 }
412 var result = [];
413 array.forEach(function (value) {
414 result.push(format(value));
415 });
416 return result;
417 });
418 };
419 return Formatter;
420}());
421exports.Formatter = Formatter;
422function isCommunityResourcable(value) {
423 return (value && typeof (value.isCommunityResource) === "function");
424}
425exports.isCommunityResourcable = isCommunityResourcable;
426function isCommunityResource(value) {
427 return (isCommunityResourcable(value) && value.isCommunityResource());
428}
429exports.isCommunityResource = isCommunityResource;
430// Show the throttle message only once
431var throttleMessage = false;
432function showThrottleMessage() {
433 if (throttleMessage) {
434 return;
435 }
436 throttleMessage = true;
437 console.log("========= NOTICE =========");
438 console.log("Request-Rate Exceeded (this message will not be repeated)");
439 console.log("");
440 console.log("The default API keys for each service are provided as a highly-throttled,");
441 console.log("community resource for low-traffic projects and early prototyping.");
442 console.log("");
443 console.log("While your application will continue to function, we highly recommended");
444 console.log("signing up for your own API keys to improve performance, increase your");
445 console.log("request rate/limit and enable other perks, such as metrics and advanced APIs.");
446 console.log("");
447 console.log("For more details: https:/\/docs.ethers.io/api-keys/");
448 console.log("==========================");
449}
450exports.showThrottleMessage = showThrottleMessage;
451//# sourceMappingURL=formatter.js.map
\No newline at end of file