minterjs-tx
Version:
A simple module for creating, manipulating and signing Minter transactions
235 lines (224 loc) • 9.04 kB
JavaScript
"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;