laksa-core-transaction
Version:
Transaction instance for laksa
527 lines (462 loc) • 15.5 kB
JavaScript
/**
* 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;