UNPKG

laksa-core-transaction

Version:

Transaction instance for laksa

527 lines (462 loc) 15.5 kB
/** * This source code is being disclosed to you solely for the purpose of your participation in * testing Zilliqa and Laksa. You may view, compile and run the code for that purpose and pursuant to * the protocols and algorithms that are programmed into, and intended by, the code. You may * not do anything else with the code without express permission from Zilliqa Research Pte. Ltd., * including modifying or publishing the code (or any part of it), and developing or forming * another public or private blockchain network. This source code is provided ‘as is’ and no * warranties are given as to title or non-infringement, merchantability or fitness for purpose * and, to the extent permitted by law, all liability for your use of the code is disclaimed. * Some programs in this code are governed by the GNU General Public License v3.0 (available at * https://www.gnu.org/licenses/gpl-3.0.en.html) (‘GPLv3’). The programs that are governed by * GPLv3.0 are those programs that are located in the folders src/depends and tests/depends * and which include a reference to GPLv3 in their program files. */ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } require('core-js/modules/es6.object.freeze'); var _regeneratorRuntime = _interopDefault(require('@babel/runtime/regenerator')); require('core-js/modules/es6.promise'); require('regenerator-runtime/runtime'); var _asyncToGenerator = _interopDefault(require('@babel/runtime/helpers/asyncToGenerator')); require('core-js/modules/es6.string.repeat'); require('core-js/modules/es6.regexp.to-string'); var _objectSpread = _interopDefault(require('@babel/runtime/helpers/objectSpread')); var _classCallCheck = _interopDefault(require('@babel/runtime/helpers/classCallCheck')); var _createClass = _interopDefault(require('@babel/runtime/helpers/createClass')); var laksaCoreCrypto = require('laksa-core-crypto'); var _possibleConstructorReturn = _interopDefault(require('@babel/runtime/helpers/possibleConstructorReturn')); var _getPrototypeOf = _interopDefault(require('@babel/runtime/helpers/getPrototypeOf')); var _inherits = _interopDefault(require('@babel/runtime/helpers/inherits')); var laksaShared = require('laksa-shared'); /** * @function sleep * @param {Number} ms - miliSeconds * @return {Promise<Function>} {description} */ var sleep = /*#__PURE__*/ function () { var _ref = _asyncToGenerator( /*#__PURE__*/ _regeneratorRuntime.mark(function _callee(ms) { return _regeneratorRuntime.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: return _context.abrupt("return", new Promise(function (resolve) { setTimeout(function () { return resolve(); }, ms); })); case 1: case "end": return _context.stop(); } } }, _callee); })); return function sleep(_x) { return _ref.apply(this, arguments); }; }(); var TxStatus = Object.freeze({ Pending: 'Pending', Initialised: 'Initialised', Signed: 'Signed', Confirmed: 'Confirmed', Rejected: 'Rejected' }); /** * @class Transaction * @description Createa a Transaction instance * @param {Object} params - params object * @param {Messenger} messenger - messenger instance * @param {String} status - txstatus * @param {Boolean} toDs - send to Shard * @return {Transaction} = Transaction instance */ var Transaction = /*#__PURE__*/ function () { function Transaction(params, messenger) { var status = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : TxStatus.Initialised; var toDS = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false; _classCallCheck(this, Transaction); // params this.version = params.version; this.TranID = params.TranID; this.toAddr = laksaCoreCrypto.getAddress(params.toAddr, [laksaCoreCrypto.AddressType.bech32, laksaCoreCrypto.AddressType.checkSum], laksaCoreCrypto.AddressType.checkSum); this.nonce = params.nonce; this.pubKey = params.pubKey; this.amount = params.amount; this.code = params.code || ''; this.data = params.data || ''; this.signature = params.signature; this.gasPrice = params.gasPrice; this.gasLimit = params.gasLimit; this.receipt = params.receipt; // status this.status = status; this.messenger = messenger; this.toDS = toDS; } /** * @function confirm * @memberof Transaction * @param {BaseTx} params */ _createClass(Transaction, [{ key: "setMessenger", value: function setMessenger(messenger) { this.messenger = messenger; } /** * @param {TxStatus} status * @returns {undefined} */ }, { key: "setStatus", value: function setStatus(status) { this.status = status; return this; } }, { key: "isPending", /** * @function isPending * * @returns {boolean} */ value: function isPending() { return this.status === TxStatus.Pending; } /** * @function isInitialised * * @returns {boolean} */ }, { key: "isInitialised", value: function isInitialised() { return this.status === TxStatus.Initialised; } /** * @function isRejected * * @returns {boolean} */ }, { key: "isSigned", value: function isSigned() { return this.status === TxStatus.Signed; } /** * @function isConfirmed * * @returns {boolean} */ }, { key: "isConfirmed", value: function isConfirmed() { return this.status === TxStatus.Confirmed; } /** * @function isRejected * * @returns {boolean} */ }, { key: "isRejected", value: function isRejected() { return this.status === TxStatus.Rejected; } }, { key: "sendTransaction", value: function () { var _sendTransaction = _asyncToGenerator( /*#__PURE__*/ _regeneratorRuntime.mark(function _callee() { var raw, result, TranID; return _regeneratorRuntime.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: if (this.signature) { _context.next = 2; break; } throw new Error('The Transaction has not been signed'); case 2: _context.prev = 2; raw = this.txParams; _context.next = 6; return this.messenger.send('CreateTransaction', _objectSpread({}, raw, { amount: raw.amount.toString(), gasLimit: raw.gasLimit.toString(), gasPrice: raw.gasPrice.toString(), priority: this.toDS })); case 6: result = _context.sent; TranID = result.TranID; if (TranID) { _context.next = 12; break; } throw new Error('Transaction fail'); case 12: this.TranID = TranID; this.status = TxStatus.Pending; return _context.abrupt("return", { transaction: this, response: result }); case 15: _context.next = 20; break; case 17: _context.prev = 17; _context.t0 = _context["catch"](2); throw _context.t0; case 20: case "end": return _context.stop(); } } }, _callee, this, [[2, 17]]); })); function sendTransaction() { return _sendTransaction.apply(this, arguments); } return sendTransaction; }() // /** // * confirmReceipt // * // * Similar to the Promise API. This sets the Transaction instance to a state // * of pending. Calling this function kicks off a passive loop that polls the // * lookup node for confirmation on the txHash. // * // * The polls are performed with a linear backoff: // * // * `const delay = interval * attempt` // * // * This is a low-level method that you should generally not have to use // * directly. // */ /* * * @param {string} txHash * @param {number} maxAttempts * @param {number} initial interval in milliseconds * @returns {Promise<Transaction>} */ }, { key: "confirm", value: function () { var _confirm = _asyncToGenerator( /*#__PURE__*/ _regeneratorRuntime.mark(function _callee2(txHash) { var maxAttempts, interval, attempt, _args2 = arguments; return _regeneratorRuntime.wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: maxAttempts = _args2.length > 1 && _args2[1] !== undefined ? _args2[1] : 20; interval = _args2.length > 2 && _args2[2] !== undefined ? _args2[2] : 1000; this.status = TxStatus.Pending; attempt = 0; case 4: if (!(attempt < maxAttempts)) { _context2.next = 22; break; } _context2.prev = 5; _context2.next = 8; return this.trackTx(txHash); case 8: if (!_context2.sent) { _context2.next = 10; break; } return _context2.abrupt("return", this); case 10: _context2.next = 16; break; case 12: _context2.prev = 12; _context2.t0 = _context2["catch"](5); this.status = TxStatus.Rejected; throw _context2.t0; case 16: if (!(attempt + 1 < maxAttempts)) { _context2.next = 19; break; } _context2.next = 19; return sleep(interval * attempt); case 19: attempt += 1; _context2.next = 4; break; case 22: this.status = TxStatus.Rejected; throw new Error("The transaction is still not confirmed after ".concat(maxAttempts, " attempts.")); case 24: case "end": return _context2.stop(); } } }, _callee2, this, [[5, 12]]); })); function confirm(_x) { return _confirm.apply(this, arguments); } return confirm; }() }, { key: "map", value: function map(fn) { var newParams = fn(this.txParams); this.setParams(newParams); return this; } }, { key: "setParams", value: function setParams(params) { this.version = params.version; this.TranID = params.TranID; this.toAddr = laksaCoreCrypto.getAddress(params.toAddr, [laksaCoreCrypto.AddressType.bech32, laksaCoreCrypto.AddressType.checkSum], laksaCoreCrypto.AddressType.checkSum); this.nonce = params.nonce; this.pubKey = params.pubKey; this.amount = params.amount; this.code = params.code; this.data = params.data; this.signature = params.signature; this.gasPrice = params.gasPrice; this.gasLimit = params.gasLimit; this.receipt = params.receipt; } }, { key: "trackTx", value: function () { var _trackTx = _asyncToGenerator( /*#__PURE__*/ _regeneratorRuntime.mark(function _callee3(txHash) { var res; return _regeneratorRuntime.wrap(function _callee3$(_context3) { while (1) { switch (_context3.prev = _context3.next) { case 0: _context3.next = 2; return this.messenger.send('GetTransaction', txHash); case 2: res = _context3.sent; if (!(res.responseType === 'error')) { _context3.next = 5; break; } return _context3.abrupt("return", false); case 5: this.TranID = res.ID; this.receipt = res.receipt; this.status = this.receipt && this.receipt.success ? TxStatus.Confirmed : TxStatus.Rejected; return _context3.abrupt("return", true); case 9: case "end": return _context3.stop(); } } }, _callee3, this); })); function trackTx(_x2) { return _trackTx.apply(this, arguments); } return trackTx; }() }, { key: "bytes", get: function get() { return laksaCoreCrypto.encodeTransactionProto(this.txParams); } }, { key: "txParams", get: function get() { try { return { version: this.version, // this.messenger.setTransactionVersion(this.version), TranID: this.TranID, toAddr: laksaCoreCrypto.getAddress(this.toAddr, [laksaCoreCrypto.AddressType.bech32, laksaCoreCrypto.AddressType.checkSum], laksaCoreCrypto.AddressType.checkSum), // after updated to the core, it will not slice nonce: this.nonce, pubKey: this.pubKey, amount: this.amount, gasPrice: this.gasPrice, gasLimit: this.gasLimit, code: this.code, data: this.data, signature: this.signature, receipt: this.receipt }; } catch (error) { throw error; } } }, { key: "senderAddress", get: function get() { if (!this.pubKey) { return String(0).repeat(40); } return laksaCoreCrypto.getAddressFromPublicKey(this.pubKey); } }], [{ key: "confirm", value: function confirm(params, messenger) { return new Transaction(params, messenger, TxStatus.Confirmed); } /** *@function reject * @memberof Transaction * @param {BaseTx} params */ }, { key: "reject", value: function reject(params, messenger) { return new Transaction(params, messenger, TxStatus.Rejected); } }]); return Transaction; }(); /** * @class Transactions */ var Transactions = /*#__PURE__*/ function (_Core) { _inherits(Transactions, _Core); function Transactions(messenger, signer) { var _this; _classCallCheck(this, Transactions); _this = _possibleConstructorReturn(this, _getPrototypeOf(Transactions).call(this)); _this.messenger = messenger; _this.signer = signer; return _this; } _createClass(Transactions, [{ key: "new", value: function _new(txParams) { var toDS = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; return new Transaction(txParams, this.messenger, TxStatus.Initialised, toDS); } }]); return Transactions; }(laksaShared.Core); exports.Transaction = Transaction; exports.Transactions = Transactions; exports.sleep = sleep; exports.TxStatus = TxStatus;