UNPKG

@aeternity/aepp-sdk

Version:
442 lines (394 loc) 17.8 kB
import _Object$keys from "@babel/runtime-corejs3/core-js-stable/object/keys"; import _Object$getOwnPropertySymbols from "@babel/runtime-corejs3/core-js-stable/object/get-own-property-symbols"; import _filterInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/filter"; import _Object$getOwnPropertyDescriptor from "@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptor"; import _forEachInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/for-each"; import _Object$getOwnPropertyDescriptors from "@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptors"; import _Object$defineProperties from "@babel/runtime-corejs3/core-js-stable/object/define-properties"; import _Object$defineProperty from "@babel/runtime-corejs3/core-js-stable/object/define-property"; import _defineProperty from "@babel/runtime-corejs3/helpers/defineProperty"; import _asyncToGenerator from "@babel/runtime-corejs3/helpers/asyncToGenerator"; import _toConsumableArray from "@babel/runtime-corejs3/helpers/toConsumableArray"; import _slicedToArray from "@babel/runtime-corejs3/helpers/slicedToArray"; import _regeneratorRuntime from "@babel/runtime-corejs3/regenerator"; function ownKeys(object, enumerableOnly) { var keys = _Object$keys(object); if (_Object$getOwnPropertySymbols) { var symbols = _Object$getOwnPropertySymbols(object); if (enumerableOnly) symbols = _filterInstanceProperty(symbols).call(symbols, function (sym) { return _Object$getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { var _context11; _forEachInstanceProperty(_context11 = ownKeys(Object(source), true)).call(_context11, function (key) { _defineProperty(target, key, source[key]); }); } else if (_Object$getOwnPropertyDescriptors) { _Object$defineProperties(target, _Object$getOwnPropertyDescriptors(source)); } else { var _context12; _forEachInstanceProperty(_context12 = ownKeys(Object(source))).call(_context12, function (key) { _Object$defineProperty(target, key, _Object$getOwnPropertyDescriptor(source, key)); }); } } return target; } import _concatInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/concat"; import _includesInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/includes"; import _reduceInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/reduce"; import _Object$entries from "@babel/runtime-corejs3/core-js-stable/object/entries"; import _parseInt from "@babel/runtime-corejs3/core-js-stable/parse-int"; import _findInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/find"; import _mapInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/map"; import { verify, decodeBase58Check, assertedType } from '../utils/crypto'; import { encode } from '../tx/builder/helpers'; import BigNumber from 'bignumber.js'; import { BASE_VERIFICATION_SCHEMA, CONTRACT_VERIFICATION_SCHEMA, MIN_GAS_PRICE, NAME_CLAIM_VERIFICATION_SCHEMA, OBJECT_ID_TX_TYPE, OBJECT_TAG_SIGNED_TRANSACTION, PROTOCOL_VM_ABI, SIGNATURE_VERIFICATION_SCHEMA, TX_TYPE } from './builder/schema'; import { buildTxHash, calculateFee, unpackTx } from './builder'; import { NodePool } from '../node-pool'; /** * Transaction validator * @module @aeternity/aepp-sdk/es/tx/validator * @export TransactionValidator * @example import { TransactionValidator } from '@aeternity/aepp-sdk' */ var VALIDATORS = { // VALIDATE SIGNATURE signature: function signature(_ref) { var rlpEncoded = _ref.rlpEncoded, signature = _ref.signature, ownerPublicKey = _ref.ownerPublicKey, _ref$networkId = _ref.networkId, networkId = _ref$networkId === void 0 ? 'ae_mainnet' : _ref$networkId; var txWithNetworkId = _concatInstanceProperty(Buffer).call(Buffer, [Buffer.from(networkId), rlpEncoded]); var txHashWithNetworkId = _concatInstanceProperty(Buffer).call(Buffer, [Buffer.from(networkId), buildTxHash(rlpEncoded, { raw: true })]); var decodedPub = decodeBase58Check(assertedType(ownerPublicKey, 'ak')); return verify(txWithNetworkId, signature, decodedPub) || verify(txHashWithNetworkId, signature, decodedPub); }, // VALIDATE IF ENOUGH FEE insufficientFee: function insufficientFee(_ref2) { var minFee = _ref2.minFee, fee = _ref2.fee; return BigNumber(minFee).lte(BigNumber(fee)); }, // VALIDATE IF TTL VALID expiredTTL: function expiredTTL(_ref3) { var ttl = _ref3.ttl, height = _ref3.height; return BigNumber(ttl).eq(0) || BigNumber(ttl).gte(BigNumber(height)); }, // Insufficient Balance for Amount plus Fee insufficientBalanceForAmountFee: function insufficientBalanceForAmountFee(_ref4) { var balance = _ref4.balance, _ref4$amount = _ref4.amount, amount = _ref4$amount === void 0 ? 0 : _ref4$amount, fee = _ref4.fee; return BigNumber(balance).gte(BigNumber(amount).plus(fee)); }, // Insufficient Balance for Amount insufficientBalanceForAmount: function insufficientBalanceForAmount(_ref5) { var balance = _ref5.balance, _ref5$amount = _ref5.amount, amount = _ref5$amount === void 0 ? 0 : _ref5$amount; return BigNumber(balance).gte(BigNumber(amount)); }, // IF NONCE USED nonceUsed: function nonceUsed(_ref6) { var accountNonce = _ref6.accountNonce, nonce = _ref6.nonce; return BigNumber(nonce).gt(BigNumber(accountNonce)); }, // IF NONCE TO HIGH nonceHigh: function nonceHigh(_ref7) { var accountNonce = _ref7.accountNonce, nonce = _ref7.nonce; return !BigNumber(nonce).gt(BigNumber(accountNonce).plus(1)); }, minGasPrice: function minGasPrice(_ref8) { var gasPrice = _ref8.gasPrice; return isNaN(gasPrice) || BigNumber(gasPrice).gte(BigNumber(MIN_GAS_PRICE)); }, // VM/ABI version validation based on consensus protocol version vmAndAbiVersion: function vmAndAbiVersion(_ref9) { var _context, _context2; var ctVersion = _ref9.ctVersion, abiVersion = _ref9.abiVersion, consensusProtocolVersion = _ref9.consensusProtocolVersion, txType = _ref9.txType; // If not contract tx if (!ctVersion) ctVersion = { abiVersion: abiVersion }; var supportedProtocol = PROTOCOL_VM_ABI[consensusProtocolVersion]; // If protocol not implemented if (!supportedProtocol) return true; // If protocol for tx type not implemented var txProtocol = supportedProtocol[txType]; return !_includesInstanceProperty(_context = _reduceInstanceProperty(_context2 = _Object$entries(ctVersion)).call(_context2, function (acc, _ref10) { var _context3, _context4; var _ref11 = _slicedToArray(_ref10, 2), key = _ref11[0], value = _ref11[1]; return _concatInstanceProperty(_context3 = []).call(_context3, _toConsumableArray(acc), [value === undefined ? true : _includesInstanceProperty(_context4 = txProtocol[key]).call(_context4, _parseInt(value))]); }, [])).call(_context, false); }, insufficientBalanceForFeeNameFee: function insufficientBalanceForFeeNameFee(_ref12) { var nameFee = _ref12.nameFee, fee = _ref12.fee, balance = _ref12.balance, VSN = _ref12.VSN; return VSN === 1 || BigNumber(balance).gte(BigNumber(nameFee).plus(fee)); } }; var resolveDataForBase = /*#__PURE__*/function () { var _ref14 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(chain, _ref13) { var ownerPublicKey, accountNonce, accountBalance, _yield$chain$api$getA, nonce, balance; return _regeneratorRuntime.wrap(function _callee$(_context5) { while (1) { switch (_context5.prev = _context5.next) { case 0: ownerPublicKey = _ref13.ownerPublicKey; accountNonce = 0; accountBalance = 0; _context5.prev = 3; _context5.next = 6; return chain.api.getAccountByPubkey(ownerPublicKey); case 6: _yield$chain$api$getA = _context5.sent; nonce = _yield$chain$api$getA.nonce; balance = _yield$chain$api$getA.balance; accountNonce = nonce; accountBalance = balance; _context5.next = 16; break; case 13: _context5.prev = 13; _context5.t0 = _context5["catch"](3); console.log('We can not get info about this publicKey'); case 16: _context5.t1 = _objectSpread; _context5.next = 19; return chain.api.getCurrentKeyBlockHeight(); case 19: _context5.t2 = _context5.sent.height; _context5.t3 = accountBalance; _context5.t4 = accountNonce; _context5.t5 = ownerPublicKey; _context5.t6 = { height: _context5.t2, balance: _context5.t3, accountNonce: _context5.t4, ownerPublicKey: _context5.t5 }; _context5.t7 = chain.getNodeInfo(); return _context5.abrupt("return", (0, _context5.t1)(_context5.t6, _context5.t7)); case 26: case "end": return _context5.stop(); } } }, _callee, null, [[3, 13]]); })); return function resolveDataForBase(_x, _x2) { return _ref14.apply(this, arguments); }; }(); // Verification using SCHEMA var verifySchema = function verifySchema(schema, data) { // Verify through schema return _reduceInstanceProperty(schema).call(schema, function (acc, _ref15) { var _ref16 = _slicedToArray(_ref15, 3), msg = _ref16[0], validatorKey = _ref16[1], _ref16$ = _ref16[2], key = _ref16$.key, type = _ref16$.type, txKey = _ref16$.txKey; if (!VALIDATORS[validatorKey](data)) acc.push({ msg: msg(data), txKey: txKey, type: type }); return acc; }, []); }; /** * Unpack and verify transaction (verify nonce, ttl, fee, signature, account balance) * @function * @alias module:@aeternity/aepp-sdk/es/tx/validator * * @param {String} txHash Base64Check transaction hash * @param {Object} [options={}] Options * @param {String} [options.networkId] networkId Use in signature verification * @return {Promise<Object>} Object with verification errors and warnings */ function unpackAndVerify(_x3) { return _unpackAndVerify.apply(this, arguments); } function _unpackAndVerify() { _unpackAndVerify = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(txHash) { var _ref18, networkId, _unpackTx, unpackedTx, rlpEncoded, txType, _context7, _unpackedTx$encodedTx, _txType, tx, signatures, rlpEncodedTx, _args2 = arguments; return _regeneratorRuntime.wrap(function _callee2$(_context8) { while (1) { switch (_context8.prev = _context8.next) { case 0: _ref18 = _args2.length > 1 && _args2[1] !== undefined ? _args2[1] : {}, networkId = _ref18.networkId; _unpackTx = unpackTx(txHash), unpackedTx = _unpackTx.tx, rlpEncoded = _unpackTx.rlpEncoded, txType = _unpackTx.txType; if (!(+unpackedTx.tag === OBJECT_TAG_SIGNED_TRANSACTION)) { _context8.next = 13; break; } _unpackedTx$encodedTx = unpackedTx.encodedTx, _txType = _unpackedTx$encodedTx.txType, tx = _unpackedTx$encodedTx.tx; signatures = _mapInstanceProperty(_context7 = unpackedTx.signatures).call(_context7, function (raw) { return { raw: raw, hash: encode(raw, 'sg') }; }); rlpEncodedTx = unpackedTx.encodedTx.rlpEncoded; _context8.next = 8; return this.verifyTx({ tx: tx, signatures: signatures, rlpEncoded: rlpEncodedTx }, networkId); case 8: _context8.t0 = _context8.sent; _context8.t1 = tx; _context8.t2 = signatures; _context8.t3 = _txType; return _context8.abrupt("return", { validation: _context8.t0, tx: _context8.t1, signatures: _context8.t2, txType: _context8.t3 }); case 13: _context8.next = 15; return this.verifyTx({ tx: unpackedTx, rlpEncoded: rlpEncoded }, networkId); case 15: _context8.t4 = _context8.sent; _context8.t5 = unpackedTx; _context8.t6 = txType; return _context8.abrupt("return", { validation: _context8.t4, tx: _context8.t5, txType: _context8.t6 }); case 19: case "end": return _context8.stop(); } } }, _callee2, this); })); return _unpackAndVerify.apply(this, arguments); } var getOwnerPublicKey = function getOwnerPublicKey(tx) { var _context6; return tx[_findInstanceProperty(_context6 = ['senderId', 'accountId', 'ownerId', 'callerId', 'oracleId', 'fromId', 'initiator', 'gaId']).call(_context6, function (key) { return tx[key]; })].replace('ok_', 'ak_'); }; /** * Verify transaction (verify nonce, ttl, fee, signature, account balance) * @function * @alias module:@aeternity/aepp-sdk/es/tx/validator * * @param {Object} [data={}] data TX data object * @param {String} [data.tx] tx Transaction hash * @param {Array} [data.signatures] signatures Transaction signature's * @param {Array} [data.rlpEncoded] rlpEncoded RLP encoded transaction * @param {String} networkId networkId Use in signature verification * @return {Promise<Array>} Object with verification errors and warnings */ function verifyTx(_x4, _x5) { return _verifyTx.apply(this, arguments); } /** * Verification for speciific txType * @param txType * @param data * @return {Array} */ function _verifyTx() { _verifyTx = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3(_ref17, networkId) { var _context9; var tx, signatures, rlpEncoded, ownerPublicKey, gas, txType, resolvedData, signatureVerification, baseVerification; return _regeneratorRuntime.wrap(function _callee3$(_context10) { while (1) { switch (_context10.prev = _context10.next) { case 0: tx = _ref17.tx, signatures = _ref17.signatures, rlpEncoded = _ref17.rlpEncoded; networkId = networkId || this.getNetworkId() || 'ae_mainnet'; // Fetch data for verification ownerPublicKey = getOwnerPublicKey(tx); gas = Object.prototype.hasOwnProperty.call(tx, 'gas') ? +tx.gas : 0; txType = OBJECT_ID_TX_TYPE[+tx.tag]; _context10.t0 = _objectSpread; _context10.t1 = _objectSpread; _context10.t2 = _objectSpread; _context10.t3 = { minFee: calculateFee(0, txType, { gas: gas, params: tx, showWarning: false }) }; _context10.next = 11; return resolveDataForBase(this, { ownerPublicKey: ownerPublicKey }); case 11: _context10.t4 = _context10.sent; _context10.t5 = (0, _context10.t2)(_context10.t3, _context10.t4); _context10.t6 = tx; _context10.t7 = (0, _context10.t1)(_context10.t5, _context10.t6); _context10.t8 = {}; _context10.t9 = { txType: txType }; resolvedData = (0, _context10.t0)(_context10.t7, _context10.t8, _context10.t9); signatureVerification = signatures && signatures.length ? verifySchema(SIGNATURE_VERIFICATION_SCHEMA, { rlpEncoded: rlpEncoded, signature: signatures[0].raw, ownerPublicKey: ownerPublicKey, networkId: networkId }) : []; baseVerification = verifySchema(BASE_VERIFICATION_SCHEMA, resolvedData); return _context10.abrupt("return", _concatInstanceProperty(_context9 = []).call(_context9, _toConsumableArray(baseVerification), _toConsumableArray(signatureVerification), _toConsumableArray(customVerification(txType, resolvedData)))); case 21: case "end": return _context10.stop(); } } }, _callee3, this); })); return _verifyTx.apply(this, arguments); } function customVerification(txType, data) { switch (txType) { case TX_TYPE.contractCreate: case TX_TYPE.contractCall: case TX_TYPE.oracleRegister: return verifySchema(CONTRACT_VERIFICATION_SCHEMA, data); case TX_TYPE.nameClaim: return verifySchema(NAME_CLAIM_VERIFICATION_SCHEMA, data); default: return []; } } /** * Transaction Validator Stamp * This stamp give us possibility to unpack and validate some of transaction properties, * to make sure we can post it to the chain * @function * @alias module:@aeternity/aepp-sdk/es/tx/validator * @rtype Stamp * @param {Object} [options={}] - Initializer object * @param {Object} [options.url] - Node url * @param {Object} [options.internalUrl] - Node internal url * @return {Object} Transaction Validator instance * @example TransactionValidator({url: 'https://testnet.aeternity.io'}) */ var TransactionValidator = NodePool.compose({ methods: { verifyTx: verifyTx, unpackAndVerify: unpackAndVerify } }); export default TransactionValidator; //# sourceMappingURL=validator.js.map