formatter.js 18 KB

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