UNPKG

laksa-core-transaction

Version:

Transaction instance for laksa

360 lines (305 loc) 10.2 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. */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('laksa-core-crypto'), require('laksa-shared')) : typeof define === 'function' && define.amd ? define(['exports', 'laksa-core-crypto', 'laksa-shared'], factory) : (factory((global.Laksa = {}),global.laksaCoreCrypto,global.laksaShared)); }(this, (function (exports,laksaCoreCrypto,laksaShared) { 'use strict'; function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; } /** * @function sleep * @param {Number} ms - miliSeconds * @return {Promise<Function>} {description} */ const sleep = async ms => new Promise(resolve => { setTimeout(() => resolve(), ms); }); const 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 */ class Transaction { constructor(params, messenger, status = TxStatus.Initialised, toDS = false) { // 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 */ static confirm(params, messenger) { return new Transaction(params, messenger, TxStatus.Confirmed); } /** *@function reject * @memberof Transaction * @param {BaseTx} params */ static reject(params, messenger) { return new Transaction(params, messenger, TxStatus.Rejected); } setMessenger(messenger) { this.messenger = messenger; } /** * @param {TxStatus} status * @returns {undefined} */ setStatus(status) { this.status = status; return this; } get bytes() { return laksaCoreCrypto.encodeTransactionProto(this.txParams); } get txParams() { 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; } } get senderAddress() { if (!this.pubKey) { return String(0).repeat(40); } return laksaCoreCrypto.getAddressFromPublicKey(this.pubKey); } /** * @function isPending * * @returns {boolean} */ isPending() { return this.status === TxStatus.Pending; } /** * @function isInitialised * * @returns {boolean} */ isInitialised() { return this.status === TxStatus.Initialised; } /** * @function isRejected * * @returns {boolean} */ isSigned() { return this.status === TxStatus.Signed; } /** * @function isConfirmed * * @returns {boolean} */ isConfirmed() { return this.status === TxStatus.Confirmed; } /** * @function isRejected * * @returns {boolean} */ isRejected() { return this.status === TxStatus.Rejected; } async sendTransaction() { if (!this.signature) { throw new Error('The Transaction has not been signed'); } try { const raw = this.txParams; const result = await this.messenger.send('CreateTransaction', _objectSpread({}, raw, { amount: raw.amount.toString(), gasLimit: raw.gasLimit.toString(), gasPrice: raw.gasPrice.toString(), priority: this.toDS })); const { TranID } = result; if (!TranID) { throw new Error('Transaction fail'); } else { this.TranID = TranID; this.status = TxStatus.Pending; return { transaction: this, response: result }; } } catch (error) { throw error; } } // /** // * 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>} */ async confirm(txHash, maxAttempts = 20, interval = 1000) { this.status = TxStatus.Pending; for (let attempt = 0; attempt < maxAttempts; attempt += 1) { try { if (await this.trackTx(txHash)) { return this; } } catch (err) { this.status = TxStatus.Rejected; throw err; } if (attempt + 1 < maxAttempts) { await sleep(interval * attempt); } } this.status = TxStatus.Rejected; throw new Error(`The transaction is still not confirmed after ${maxAttempts} attempts.`); } map(fn) { const newParams = fn(this.txParams); this.setParams(newParams); return this; } 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; } async trackTx(txHash) { // TODO: regex validation for txHash so we don't get garbage const res = await this.messenger.send('GetTransaction', txHash); if (res.responseType === 'error') { return false; } this.TranID = res.ID; this.receipt = res.receipt; this.status = this.receipt && this.receipt.success ? TxStatus.Confirmed : TxStatus.Rejected; return true; } } /** * @class Transactions */ class Transactions extends laksaShared.Core { constructor(messenger, signer) { super(); this.messenger = messenger; this.signer = signer; } new(txParams, toDS = false) { return new Transaction(txParams, this.messenger, TxStatus.Initialised, toDS); } } exports.Transaction = Transaction; exports.Transactions = Transactions; exports.sleep = sleep; exports.TxStatus = TxStatus; Object.defineProperty(exports, '__esModule', { value: true }); })));