UNPKG

minterjs-tx

Version:

A simple module for creating, manipulating and signing Minter transactions

235 lines (224 loc) 9.04 kB
"use strict"; function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var rlp = _interopRequireWildcard(require("rlp")); var _bn = _interopRequireDefault(require("bn.js")); var _hash = require("ethereumjs-util/dist/hash.js"); var _account = require("ethereumjs-util/dist/account.js"); var _signature = require("ethereumjs-util/dist/signature.js"); var _bytes = require("ethereumjs-util/dist/bytes.js"); var _defineProperties2 = _interopRequireDefault(require("./define-properties.js")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } // secp256k1n/2 var N_DIV_2 = new _bn["default"]('7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0', 16); var Tx = /*#__PURE__*/function () { function Tx(data) { _classCallCheck(this, Tx); data = data || {}; // Define Properties var fields = [{ name: 'nonce', length: 32, allowLess: true }, { name: 'chainId', length: 1 }, { name: 'gasPrice', length: 32, allowLess: true }, { name: 'gasCoin', length: 4, allowLess: true }, { name: 'type', length: 1 }, { name: 'data', alias: 'input' }, { name: 'payload', allowZero: true, "default": Buffer.from([]) }, { name: 'serviceData', allowZero: true, "default": Buffer.from([]) }, { name: 'signatureType', length: 1, allowLess: true, "default": Buffer.from([]) }, { name: 'signatureData', "default": Buffer.from([]) }]; /** * @TODO deprecated @see https://github.com/ethereumjs/ethereumjs-account/issues/29 @see https://github.com/ethereumjs/ethereumjs-tx/issues/151 * Returns the rlp encoding of the transaction * @method serialize * @return {Buffer} * @memberof Transaction * @name serialize */ // attached serialize (0, _defineProperties2["default"])(this, fields, data); /** * @property {Buffer} from (read only) sender address of this transaction, mathematically derived from other parameters. * @name from * @memberof Transaction */ Object.defineProperty(this, 'from', { enumerable: true, configurable: true, get: this.getSenderAddress.bind(this) }); } /** * Computes a sha3-256 hash of the serialized tx * @param {Boolean} [includeSignature=true] whether or not to include the signature * @return {Buffer} */ _createClass(Tx, [{ key: "hash", value: function hash(includeSignature) { if (includeSignature === undefined) { includeSignature = true; } // EIP155 spec: // when computing the hash of a transaction for purposes of signing or recovering, // instead of hashing only the first six elements (ie. nonce, gasprice, startgas, to, value, data), // hash nine elements, with v replaced by CHAIN_ID, r = 0 and s = 0 var items; if (includeSignature) { items = this.raw; } else { // hash everything except signatureData items = this.raw.slice(0, -1); } // create hash return (0, _hash.rlphash)(items); } }, { key: "isSignatureTypeSingle", value: function isSignatureTypeSingle() { return (0, _bytes.bufferToInt)(this.signatureType) === 1; } }, { key: "isSignatureTypeMulti", value: function isSignatureTypeMulti() { return (0, _bytes.bufferToInt)(this.signatureType) === 2; } /** * returns the sender's address * @return {Buffer} */ }, { key: "getSenderAddress", value: function getSenderAddress() { if (this._from) { return this._from; } if (this.isSignatureTypeMulti()) { var multiSignature = rlp.decode(this.signatureData); this._from = multiSignature[0]; return this._from; } var publicKey = this.getSenderPublicKey(); this._from = (0, _account.publicToAddress)(publicKey); return this._from; } }, { key: "getSenderAddressString", value: function getSenderAddressString() { return "Mx".concat(this.getSenderAddress().toString('hex')); } /** * returns the public key of the sender * @return {Buffer} */ }, { key: "getSenderPublicKey", value: function getSenderPublicKey() { // eslint-disable-next-line unicorn/explicit-length-check if (!this._senderPublicKey || !this._senderPublicKey.length) { // eslint-disable-next-line unicorn/no-lonely-if if (!this.verifySignature()) { throw new Error('Invalid Signature'); } } return this._senderPublicKey; } /** * Determines if the signature is valid * @return {Boolean} */ }, { key: "verifySignature", value: function verifySignature() { var _this = this; if (this.isSignatureTypeSingle()) { // Single signature var vrs = rlp.decode(this.signatureData); var messageHash = this.hash(false); return this._verifySignature(messageHash, vrs); } else { // Multi signature var multiSignature = rlp.decode(this.signatureData); var _messageHash = this.hash(false); var hasErrors = multiSignature[1].some(function (item) { return !_this._verifySignature(_messageHash, item); }); return !hasErrors; } } }, { key: "_verifySignature", value: function _verifySignature(messageHash, vrs) { // All transaction signatures whose s-value is greater than secp256k1n/2 are considered invalid. if (new _bn["default"](vrs[2]).cmp(N_DIV_2) === 1) { return false; } try { var v = (0, _bytes.bufferToInt)(vrs[0]); var senderPublicKey = (0, _signature.ecrecover)(messageHash, v, vrs[1], vrs[2]); if (this.isSignatureTypeSingle()) { this._senderPublicKey = senderPublicKey; } return !!senderPublicKey; } catch (error) { return false; } } /** * validates the signature and checks to see if it has enough gas * @param {Boolean} [stringError=false] whether to return a string with a description of why the validation failed or return a Bloolean * @return {Boolean|String} */ }, { key: "validate", value: function validate(stringError) { var errors = []; if (!this.verifySignature()) { errors.push('Invalid Signature'); } if (stringError === undefined || stringError === false) { return errors.length === 0; } else { return errors.join(' '); } } }]); return Tx; }(); var _default = Tx; exports["default"] = _default;