index.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. "use strict";
  2. var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
  3. if (k2 === undefined) k2 = k;
  4. Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
  5. }) : (function(o, m, k, k2) {
  6. if (k2 === undefined) k2 = k;
  7. o[k2] = m[k];
  8. }));
  9. var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
  10. Object.defineProperty(o, "default", { enumerable: true, value: v });
  11. }) : function(o, v) {
  12. o["default"] = v;
  13. });
  14. var __importStar = (this && this.__importStar) || function (mod) {
  15. if (mod && mod.__esModule) return mod;
  16. var result = {};
  17. if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
  18. __setModuleDefault(result, mod);
  19. return result;
  20. };
  21. Object.defineProperty(exports, "__esModule", { value: true });
  22. exports.parse = exports.serialize = exports.accessListify = exports.recoverAddress = exports.computeAddress = exports.TransactionTypes = void 0;
  23. var address_1 = require("@ethersproject/address");
  24. var bignumber_1 = require("@ethersproject/bignumber");
  25. var bytes_1 = require("@ethersproject/bytes");
  26. var constants_1 = require("@ethersproject/constants");
  27. var keccak256_1 = require("@ethersproject/keccak256");
  28. var properties_1 = require("@ethersproject/properties");
  29. var RLP = __importStar(require("@ethersproject/rlp"));
  30. var signing_key_1 = require("@ethersproject/signing-key");
  31. var logger_1 = require("@ethersproject/logger");
  32. var _version_1 = require("./_version");
  33. var logger = new logger_1.Logger(_version_1.version);
  34. var TransactionTypes;
  35. (function (TransactionTypes) {
  36. TransactionTypes[TransactionTypes["legacy"] = 0] = "legacy";
  37. TransactionTypes[TransactionTypes["eip2930"] = 1] = "eip2930";
  38. TransactionTypes[TransactionTypes["eip1559"] = 2] = "eip1559";
  39. })(TransactionTypes = exports.TransactionTypes || (exports.TransactionTypes = {}));
  40. ;
  41. ///////////////////////////////
  42. function handleAddress(value) {
  43. if (value === "0x") {
  44. return null;
  45. }
  46. return (0, address_1.getAddress)(value);
  47. }
  48. function handleNumber(value) {
  49. if (value === "0x") {
  50. return constants_1.Zero;
  51. }
  52. return bignumber_1.BigNumber.from(value);
  53. }
  54. // Legacy Transaction Fields
  55. var transactionFields = [
  56. { name: "nonce", maxLength: 32, numeric: true },
  57. { name: "gasPrice", maxLength: 32, numeric: true },
  58. { name: "gasLimit", maxLength: 32, numeric: true },
  59. { name: "to", length: 20 },
  60. { name: "value", maxLength: 32, numeric: true },
  61. { name: "data" },
  62. ];
  63. var allowedTransactionKeys = {
  64. chainId: true, data: true, gasLimit: true, gasPrice: true, nonce: true, to: true, type: true, value: true
  65. };
  66. function computeAddress(key) {
  67. var publicKey = (0, signing_key_1.computePublicKey)(key);
  68. return (0, address_1.getAddress)((0, bytes_1.hexDataSlice)((0, keccak256_1.keccak256)((0, bytes_1.hexDataSlice)(publicKey, 1)), 12));
  69. }
  70. exports.computeAddress = computeAddress;
  71. function recoverAddress(digest, signature) {
  72. return computeAddress((0, signing_key_1.recoverPublicKey)((0, bytes_1.arrayify)(digest), signature));
  73. }
  74. exports.recoverAddress = recoverAddress;
  75. function formatNumber(value, name) {
  76. var result = (0, bytes_1.stripZeros)(bignumber_1.BigNumber.from(value).toHexString());
  77. if (result.length > 32) {
  78. logger.throwArgumentError("invalid length for " + name, ("transaction:" + name), value);
  79. }
  80. return result;
  81. }
  82. function accessSetify(addr, storageKeys) {
  83. return {
  84. address: (0, address_1.getAddress)(addr),
  85. storageKeys: (storageKeys || []).map(function (storageKey, index) {
  86. if ((0, bytes_1.hexDataLength)(storageKey) !== 32) {
  87. logger.throwArgumentError("invalid access list storageKey", "accessList[" + addr + ":" + index + "]", storageKey);
  88. }
  89. return storageKey.toLowerCase();
  90. })
  91. };
  92. }
  93. function accessListify(value) {
  94. if (Array.isArray(value)) {
  95. return value.map(function (set, index) {
  96. if (Array.isArray(set)) {
  97. if (set.length > 2) {
  98. logger.throwArgumentError("access list expected to be [ address, storageKeys[] ]", "value[" + index + "]", set);
  99. }
  100. return accessSetify(set[0], set[1]);
  101. }
  102. return accessSetify(set.address, set.storageKeys);
  103. });
  104. }
  105. var result = Object.keys(value).map(function (addr) {
  106. var storageKeys = value[addr].reduce(function (accum, storageKey) {
  107. accum[storageKey] = true;
  108. return accum;
  109. }, {});
  110. return accessSetify(addr, Object.keys(storageKeys).sort());
  111. });
  112. result.sort(function (a, b) { return (a.address.localeCompare(b.address)); });
  113. return result;
  114. }
  115. exports.accessListify = accessListify;
  116. function formatAccessList(value) {
  117. return accessListify(value).map(function (set) { return [set.address, set.storageKeys]; });
  118. }
  119. function _serializeEip1559(transaction, signature) {
  120. // If there is an explicit gasPrice, make sure it matches the
  121. // EIP-1559 fees; otherwise they may not understand what they
  122. // think they are setting in terms of fee.
  123. if (transaction.gasPrice != null) {
  124. var gasPrice = bignumber_1.BigNumber.from(transaction.gasPrice);
  125. var maxFeePerGas = bignumber_1.BigNumber.from(transaction.maxFeePerGas || 0);
  126. if (!gasPrice.eq(maxFeePerGas)) {
  127. logger.throwArgumentError("mismatch EIP-1559 gasPrice != maxFeePerGas", "tx", {
  128. gasPrice: gasPrice,
  129. maxFeePerGas: maxFeePerGas
  130. });
  131. }
  132. }
  133. var fields = [
  134. formatNumber(transaction.chainId || 0, "chainId"),
  135. formatNumber(transaction.nonce || 0, "nonce"),
  136. formatNumber(transaction.maxPriorityFeePerGas || 0, "maxPriorityFeePerGas"),
  137. formatNumber(transaction.maxFeePerGas || 0, "maxFeePerGas"),
  138. formatNumber(transaction.gasLimit || 0, "gasLimit"),
  139. ((transaction.to != null) ? (0, address_1.getAddress)(transaction.to) : "0x"),
  140. formatNumber(transaction.value || 0, "value"),
  141. (transaction.data || "0x"),
  142. (formatAccessList(transaction.accessList || []))
  143. ];
  144. if (signature) {
  145. var sig = (0, bytes_1.splitSignature)(signature);
  146. fields.push(formatNumber(sig.recoveryParam, "recoveryParam"));
  147. fields.push((0, bytes_1.stripZeros)(sig.r));
  148. fields.push((0, bytes_1.stripZeros)(sig.s));
  149. }
  150. return (0, bytes_1.hexConcat)(["0x02", RLP.encode(fields)]);
  151. }
  152. function _serializeEip2930(transaction, signature) {
  153. var fields = [
  154. formatNumber(transaction.chainId || 0, "chainId"),
  155. formatNumber(transaction.nonce || 0, "nonce"),
  156. formatNumber(transaction.gasPrice || 0, "gasPrice"),
  157. formatNumber(transaction.gasLimit || 0, "gasLimit"),
  158. ((transaction.to != null) ? (0, address_1.getAddress)(transaction.to) : "0x"),
  159. formatNumber(transaction.value || 0, "value"),
  160. (transaction.data || "0x"),
  161. (formatAccessList(transaction.accessList || []))
  162. ];
  163. if (signature) {
  164. var sig = (0, bytes_1.splitSignature)(signature);
  165. fields.push(formatNumber(sig.recoveryParam, "recoveryParam"));
  166. fields.push((0, bytes_1.stripZeros)(sig.r));
  167. fields.push((0, bytes_1.stripZeros)(sig.s));
  168. }
  169. return (0, bytes_1.hexConcat)(["0x01", RLP.encode(fields)]);
  170. }
  171. // Legacy Transactions and EIP-155
  172. function _serialize(transaction, signature) {
  173. (0, properties_1.checkProperties)(transaction, allowedTransactionKeys);
  174. var raw = [];
  175. transactionFields.forEach(function (fieldInfo) {
  176. var value = transaction[fieldInfo.name] || ([]);
  177. var options = {};
  178. if (fieldInfo.numeric) {
  179. options.hexPad = "left";
  180. }
  181. value = (0, bytes_1.arrayify)((0, bytes_1.hexlify)(value, options));
  182. // Fixed-width field
  183. if (fieldInfo.length && value.length !== fieldInfo.length && value.length > 0) {
  184. logger.throwArgumentError("invalid length for " + fieldInfo.name, ("transaction:" + fieldInfo.name), value);
  185. }
  186. // Variable-width (with a maximum)
  187. if (fieldInfo.maxLength) {
  188. value = (0, bytes_1.stripZeros)(value);
  189. if (value.length > fieldInfo.maxLength) {
  190. logger.throwArgumentError("invalid length for " + fieldInfo.name, ("transaction:" + fieldInfo.name), value);
  191. }
  192. }
  193. raw.push((0, bytes_1.hexlify)(value));
  194. });
  195. var chainId = 0;
  196. if (transaction.chainId != null) {
  197. // A chainId was provided; if non-zero we'll use EIP-155
  198. chainId = transaction.chainId;
  199. if (typeof (chainId) !== "number") {
  200. logger.throwArgumentError("invalid transaction.chainId", "transaction", transaction);
  201. }
  202. }
  203. else if (signature && !(0, bytes_1.isBytesLike)(signature) && signature.v > 28) {
  204. // No chainId provided, but the signature is signing with EIP-155; derive chainId
  205. chainId = Math.floor((signature.v - 35) / 2);
  206. }
  207. // We have an EIP-155 transaction (chainId was specified and non-zero)
  208. if (chainId !== 0) {
  209. raw.push((0, bytes_1.hexlify)(chainId)); // @TODO: hexValue?
  210. raw.push("0x");
  211. raw.push("0x");
  212. }
  213. // Requesting an unsigned transaction
  214. if (!signature) {
  215. return RLP.encode(raw);
  216. }
  217. // The splitSignature will ensure the transaction has a recoveryParam in the
  218. // case that the signTransaction function only adds a v.
  219. var sig = (0, bytes_1.splitSignature)(signature);
  220. // We pushed a chainId and null r, s on for hashing only; remove those
  221. var v = 27 + sig.recoveryParam;
  222. if (chainId !== 0) {
  223. raw.pop();
  224. raw.pop();
  225. raw.pop();
  226. v += chainId * 2 + 8;
  227. // If an EIP-155 v (directly or indirectly; maybe _vs) was provided, check it!
  228. if (sig.v > 28 && sig.v !== v) {
  229. logger.throwArgumentError("transaction.chainId/signature.v mismatch", "signature", signature);
  230. }
  231. }
  232. else if (sig.v !== v) {
  233. logger.throwArgumentError("transaction.chainId/signature.v mismatch", "signature", signature);
  234. }
  235. raw.push((0, bytes_1.hexlify)(v));
  236. raw.push((0, bytes_1.stripZeros)((0, bytes_1.arrayify)(sig.r)));
  237. raw.push((0, bytes_1.stripZeros)((0, bytes_1.arrayify)(sig.s)));
  238. return RLP.encode(raw);
  239. }
  240. function serialize(transaction, signature) {
  241. // Legacy and EIP-155 Transactions
  242. if (transaction.type == null || transaction.type === 0) {
  243. if (transaction.accessList != null) {
  244. logger.throwArgumentError("untyped transactions do not support accessList; include type: 1", "transaction", transaction);
  245. }
  246. return _serialize(transaction, signature);
  247. }
  248. // Typed Transactions (EIP-2718)
  249. switch (transaction.type) {
  250. case 1:
  251. return _serializeEip2930(transaction, signature);
  252. case 2:
  253. return _serializeEip1559(transaction, signature);
  254. default:
  255. break;
  256. }
  257. return logger.throwError("unsupported transaction type: " + transaction.type, logger_1.Logger.errors.UNSUPPORTED_OPERATION, {
  258. operation: "serializeTransaction",
  259. transactionType: transaction.type
  260. });
  261. }
  262. exports.serialize = serialize;
  263. function _parseEipSignature(tx, fields, serialize) {
  264. try {
  265. var recid = handleNumber(fields[0]).toNumber();
  266. if (recid !== 0 && recid !== 1) {
  267. throw new Error("bad recid");
  268. }
  269. tx.v = recid;
  270. }
  271. catch (error) {
  272. logger.throwArgumentError("invalid v for transaction type: 1", "v", fields[0]);
  273. }
  274. tx.r = (0, bytes_1.hexZeroPad)(fields[1], 32);
  275. tx.s = (0, bytes_1.hexZeroPad)(fields[2], 32);
  276. try {
  277. var digest = (0, keccak256_1.keccak256)(serialize(tx));
  278. tx.from = recoverAddress(digest, { r: tx.r, s: tx.s, recoveryParam: tx.v });
  279. }
  280. catch (error) {
  281. console.log(error);
  282. }
  283. }
  284. function _parseEip1559(payload) {
  285. var transaction = RLP.decode(payload.slice(1));
  286. if (transaction.length !== 9 && transaction.length !== 12) {
  287. logger.throwArgumentError("invalid component count for transaction type: 2", "payload", (0, bytes_1.hexlify)(payload));
  288. }
  289. var maxPriorityFeePerGas = handleNumber(transaction[2]);
  290. var maxFeePerGas = handleNumber(transaction[3]);
  291. var tx = {
  292. type: 2,
  293. chainId: handleNumber(transaction[0]).toNumber(),
  294. nonce: handleNumber(transaction[1]).toNumber(),
  295. maxPriorityFeePerGas: maxPriorityFeePerGas,
  296. maxFeePerGas: maxFeePerGas,
  297. gasPrice: null,
  298. gasLimit: handleNumber(transaction[4]),
  299. to: handleAddress(transaction[5]),
  300. value: handleNumber(transaction[6]),
  301. data: transaction[7],
  302. accessList: accessListify(transaction[8]),
  303. };
  304. // Unsigned EIP-1559 Transaction
  305. if (transaction.length === 9) {
  306. return tx;
  307. }
  308. tx.hash = (0, keccak256_1.keccak256)(payload);
  309. _parseEipSignature(tx, transaction.slice(9), _serializeEip1559);
  310. return tx;
  311. }
  312. function _parseEip2930(payload) {
  313. var transaction = RLP.decode(payload.slice(1));
  314. if (transaction.length !== 8 && transaction.length !== 11) {
  315. logger.throwArgumentError("invalid component count for transaction type: 1", "payload", (0, bytes_1.hexlify)(payload));
  316. }
  317. var tx = {
  318. type: 1,
  319. chainId: handleNumber(transaction[0]).toNumber(),
  320. nonce: handleNumber(transaction[1]).toNumber(),
  321. gasPrice: handleNumber(transaction[2]),
  322. gasLimit: handleNumber(transaction[3]),
  323. to: handleAddress(transaction[4]),
  324. value: handleNumber(transaction[5]),
  325. data: transaction[6],
  326. accessList: accessListify(transaction[7])
  327. };
  328. // Unsigned EIP-2930 Transaction
  329. if (transaction.length === 8) {
  330. return tx;
  331. }
  332. tx.hash = (0, keccak256_1.keccak256)(payload);
  333. _parseEipSignature(tx, transaction.slice(8), _serializeEip2930);
  334. return tx;
  335. }
  336. // Legacy Transactions and EIP-155
  337. function _parse(rawTransaction) {
  338. var transaction = RLP.decode(rawTransaction);
  339. if (transaction.length !== 9 && transaction.length !== 6) {
  340. logger.throwArgumentError("invalid raw transaction", "rawTransaction", rawTransaction);
  341. }
  342. var tx = {
  343. nonce: handleNumber(transaction[0]).toNumber(),
  344. gasPrice: handleNumber(transaction[1]),
  345. gasLimit: handleNumber(transaction[2]),
  346. to: handleAddress(transaction[3]),
  347. value: handleNumber(transaction[4]),
  348. data: transaction[5],
  349. chainId: 0
  350. };
  351. // Legacy unsigned transaction
  352. if (transaction.length === 6) {
  353. return tx;
  354. }
  355. try {
  356. tx.v = bignumber_1.BigNumber.from(transaction[6]).toNumber();
  357. }
  358. catch (error) {
  359. console.log(error);
  360. return tx;
  361. }
  362. tx.r = (0, bytes_1.hexZeroPad)(transaction[7], 32);
  363. tx.s = (0, bytes_1.hexZeroPad)(transaction[8], 32);
  364. if (bignumber_1.BigNumber.from(tx.r).isZero() && bignumber_1.BigNumber.from(tx.s).isZero()) {
  365. // EIP-155 unsigned transaction
  366. tx.chainId = tx.v;
  367. tx.v = 0;
  368. }
  369. else {
  370. // Signed Transaction
  371. tx.chainId = Math.floor((tx.v - 35) / 2);
  372. if (tx.chainId < 0) {
  373. tx.chainId = 0;
  374. }
  375. var recoveryParam = tx.v - 27;
  376. var raw = transaction.slice(0, 6);
  377. if (tx.chainId !== 0) {
  378. raw.push((0, bytes_1.hexlify)(tx.chainId));
  379. raw.push("0x");
  380. raw.push("0x");
  381. recoveryParam -= tx.chainId * 2 + 8;
  382. }
  383. var digest = (0, keccak256_1.keccak256)(RLP.encode(raw));
  384. try {
  385. tx.from = recoverAddress(digest, { r: (0, bytes_1.hexlify)(tx.r), s: (0, bytes_1.hexlify)(tx.s), recoveryParam: recoveryParam });
  386. }
  387. catch (error) {
  388. console.log(error);
  389. }
  390. tx.hash = (0, keccak256_1.keccak256)(rawTransaction);
  391. }
  392. tx.type = null;
  393. return tx;
  394. }
  395. function parse(rawTransaction) {
  396. var payload = (0, bytes_1.arrayify)(rawTransaction);
  397. // Legacy and EIP-155 Transactions
  398. if (payload[0] > 0x7f) {
  399. return _parse(payload);
  400. }
  401. // Typed Transaction (EIP-2718)
  402. switch (payload[0]) {
  403. case 1:
  404. return _parseEip2930(payload);
  405. case 2:
  406. return _parseEip1559(payload);
  407. default:
  408. break;
  409. }
  410. return logger.throwError("unsupported transaction type: " + payload[0], logger_1.Logger.errors.UNSUPPORTED_OPERATION, {
  411. operation: "parseTransaction",
  412. transactionType: payload[0]
  413. });
  414. }
  415. exports.parse = parse;
  416. //# sourceMappingURL=index.js.map