UNPKG

minter-js-sdk

Version:
411 lines (394 loc) 18.4 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var _asyncToGenerator = require('@babel/runtime/helpers/asyncToGenerator'); var _typeof = require('@babel/runtime/helpers/typeof'); var _defineProperty = require('@babel/runtime/helpers/defineProperty'); var _regeneratorRuntime = require('@babel/runtime/regenerator'); var minterjsUtil = require('minterjs-util'); var getCommissionPrice = require('./get-commission-price.js'); var getPoolInfo = require('./get-pool-info.js'); var replaceCoin = require('./replace-coin.js'); var index = require('../tx-data/index.js'); var tx = require('../tx.js'); function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(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 = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } // import {isCoinId, validateUint} from '../utils.js'; /** * @enum {string} */ var FEE_PRECISION_SETTING = { // value may be precise, imprecise, or even omitted AUTO: 'auto', // precise value is required PRECISE: 'precise', // some value is required but it can be imprecise IMPRECISE: 'imprecise', OMIT: 'omit' }; var PRECISION = FEE_PRECISION_SETTING; /** * @param {MinterApiInstance} apiInstance * @param {import('axios').AxiosRequestConfig} [factoryAxiosOptions] * @param {import('axios').AxiosRequestConfig} [factoryExtraAxiosOptions] * @return {EstimateTxCommissionInstance} */ function EstimateTxCommission(apiInstance, factoryAxiosOptions, factoryExtraAxiosOptions) { var getCommissionPrice$1 = getCommissionPrice(apiInstance, factoryExtraAxiosOptions); var getPoolInfo$1 = getPoolInfo(apiInstance, factoryExtraAxiosOptions); var replaceCoinSymbol = replaceCoin.ReplaceCoinSymbol(apiInstance, factoryExtraAxiosOptions); /** * @typedef {MinterFeeEstimationDirect|MinterFeeEstimationCalculate} MinterFeeEstimation */ /** * @typedef {Function} EstimateTxCommissionInstance * @param {TxParams|string} txParams * @param {object} [options] * @param {FEE_PRECISION_SETTING} [options.needGasCoinFee] * @param {FEE_PRECISION_SETTING} [options.needBaseCoinFee] * @param {FEE_PRECISION_SETTING} [options.needPriceCoinFee] * @param {boolean} [options.loose] - DEPRECATED * @param {boolean} [options.direct] - DEPRECATED * @param {import('axios').AxiosRequestConfig} [axiosOptions] - for main request (estimation) * @param {import('axios').AxiosRequestConfig} [extraAxiosOptions] - for secondary requests (commission price data, coin IDs, and pool info) * @return {Promise<MinterFeeEstimation>} */ return function estimateTxCommission(txParams) { var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, _ref$needGasCoinFee = _ref.needGasCoinFee, needGasCoinFee = _ref$needGasCoinFee === void 0 ? PRECISION.AUTO : _ref$needGasCoinFee, _ref$needBaseCoinFee = _ref.needBaseCoinFee, needBaseCoinFee = _ref$needBaseCoinFee === void 0 ? PRECISION.AUTO : _ref$needBaseCoinFee, _ref$needPriceCoinFee = _ref.needPriceCoinFee, needPriceCoinFee = _ref$needPriceCoinFee === void 0 ? PRECISION.AUTO : _ref$needPriceCoinFee, loose = _ref.loose, direct = _ref.direct; var axiosOptions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined; var extraAxiosOptions = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : undefined; axiosOptions = _objectSpread(_objectSpread({}, factoryAxiosOptions), axiosOptions); if (direct !== undefined) { // eslint-disable-next-line no-console console.warn('`direct` option in `estimateTxCommission` is deprecated, use `needGasCoinFee`, `needBaseCoinFee`, and `needPriceCoinFee` options instead'); needGasCoinFee = direct ? PRECISION.PRECISE : PRECISION.IMPRECISE; needBaseCoinFee = direct ? PRECISION.OMIT : PRECISION.IMPRECISE; needPriceCoinFee = direct ? PRECISION.OMIT : PRECISION.PRECISE; } if (loose !== undefined) { // eslint-disable-next-line no-console console.warn('`loose` option in `estimateTxCommission` is deprecated, use `needGasCoinFee`, `needBaseCoinFee`, and `needPriceCoinFee` options instead'); needGasCoinFee = !loose ? PRECISION.PRECISE : PRECISION.IMPRECISE; needBaseCoinFee = !loose ? PRECISION.OMIT : PRECISION.IMPRECISE; needPriceCoinFee = !loose ? PRECISION.OMIT : PRECISION.PRECISE; } var paramsPromise; if (_typeof(txParams) === 'object') { /* if (loose) { paramsPromise = getCoinId(txParams.gasCoin || 0, txParams.chainId, extraAxiosOptions) .then((coinId) => { validateUint(coinId, 'gasCoin'); return { ...txParams, gasCoin: coinId, }; }); } else { */ // @TODO some fields of tx data can dropped, because they don't affect fee, it will reduce coin id requests and make estimation requests more cacheable paramsPromise = replaceCoinSymbol(txParams, extraAxiosOptions); // } } else { paramsPromise = Promise.resolve(txParams); } return paramsPromise.then(function (updatedTxParams) { if (_typeof(updatedTxParams) !== 'object') { return estimateFeeDirect(updatedTxParams, axiosOptions); } else { return estimateFeeCalculate(updatedTxParams, { needGasCoinFee: needGasCoinFee, needBaseCoinFee: needBaseCoinFee, needPriceCoinFee: needPriceCoinFee, axiosOptions: axiosOptions, extraAxiosOptions: extraAxiosOptions }); } }); }; /** * @typedef {{commission: number|string}} MinterFeeEstimationDirect */ /** * @param {string|TxParams} txParams * @param {import('axios').AxiosRequestConfig} [axiosOptions] * @return {Promise<MinterFeeEstimationDirect>} */ function estimateFeeDirect(txParams, axiosOptions) { if (!txParams) { return Promise.reject(new Error('Transaction not specified')); } var tx$1; if (typeof txParams === 'string') { tx$1 = txParams; } else { tx$1 = tx.prepareTx(_objectSpread(_objectSpread({}, txParams), {}, { data: index.fillDefaultData(txParams.type, txParams.data) }), { disableValidation: true, disableDecorationParams: true }).serializeToString(); } return apiInstance.get("estimate_tx_commission/".concat(tx$1), axiosOptions).then(function (response) { return { commission: minterjsUtil.convertFromPip(response.data.commission) }; }); } /** * @typedef {MinterFeeEstimationDirect&{baseCoinCommission: number|string, priceCoinCommission: number|string, commissionPriceData: CommissionPriceData}} MinterFeeEstimationCalculate */ /** * @param {TxParams} txParams * @param {object} [options] * @param {FEE_PRECISION_SETTING} [options.needGasCoinFee] * @param {FEE_PRECISION_SETTING} [options.needBaseCoinFee] * @param {FEE_PRECISION_SETTING} [options.needPriceCoinFee] * @param {import('axios').AxiosRequestConfig} [options.axiosOptions] * @param {import('axios').AxiosRequestConfig} [options.extraAxiosOptions] - applied to secondary requests * @return {Promise<MinterFeeEstimationCalculate>} */ function estimateFeeCalculate(_x, _x2) { return _estimateFeeCalculate.apply(this, arguments); } function _estimateFeeCalculate() { _estimateFeeCalculate = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(txParams, _ref2) { var needGasCoinFee, needBaseCoinFee, needPriceCoinFee, axiosOptions, extraAxiosOptions, commissionPriceData, sameGasAndBaseCoins, sameGasAndPriceCoins, samePriceAndBaseCoins, gasDependsOnBase, baseDependsOnGas, priceCoinFee, baseCoinFee, fee, _yield$estimateFeeDir, commission; return _regeneratorRuntime.wrap(function _callee2$(_context2) { while (1) switch (_context2.prev = _context2.next) { case 0: needGasCoinFee = _ref2.needGasCoinFee, needBaseCoinFee = _ref2.needBaseCoinFee, needPriceCoinFee = _ref2.needPriceCoinFee, axiosOptions = _ref2.axiosOptions, extraAxiosOptions = _ref2.extraAxiosOptions; if (!(!txParams || _typeof(txParams) !== 'object')) { _context2.next = 3; break; } throw new TypeError('Invalid txParams'); case 3: if (needPriceCoinFee === PRECISION.AUTO) { needPriceCoinFee = PRECISION.OMIT; } if (needBaseCoinFee === PRECISION.AUTO) { needBaseCoinFee = PRECISION.OMIT; } if (needGasCoinFee === PRECISION.AUTO) { needGasCoinFee = PRECISION.PRECISE; } if (!(needPriceCoinFee !== PRECISION.OMIT)) { _context2.next = 12; break; } _context2.next = 9; return getCommissionPrice$1(extraAxiosOptions); case 9: _context2.t0 = _context2.sent; _context2.next = 13; break; case 12: _context2.t0 = undefined; case 13: commissionPriceData = _context2.t0; // coins may be same only if they both defined sameGasAndBaseCoins = isGasCoinSameAsBaseCoin(txParams.gasCoin); sameGasAndPriceCoins = isGasCoinSameAsPriceCoin(txParams.gasCoin, commissionPriceData); samePriceAndBaseCoins = isPriceCoinSameAsBaseCoin(commissionPriceData); gasDependsOnBase = sameGasAndBaseCoins && needGasCoinFee === PRECISION.IMPRECISE && needBaseCoinFee === PRECISION.IMPRECISE && commissionPriceData; baseDependsOnGas = sameGasAndBaseCoins && needGasCoinFee === PRECISION.PRECISE; // priceCoin priceCoinFee = function () { // OMIT if (!commissionPriceData) { return undefined; } // PRECISE var feePrice = new minterjsUtil.FeePrice(commissionPriceData); return feePrice.getFeeValue(txParams.type, getFeePriceOptionsFromTxParams(txParams, true)); }(); // baseCoin _context2.next = 22; return _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() { var priceCoinPool; return _regeneratorRuntime.wrap(function _callee$(_context) { while (1) switch (_context.prev = _context.next) { case 0: if (!samePriceAndBaseCoins) { _context.next = 2; break; } return _context.abrupt("return", priceCoinFee); case 2: if (!baseDependsOnGas) { _context.next = 4; break; } return _context.abrupt("return", undefined); case 4: if (!(needBaseCoinFee === PRECISION.OMIT)) { _context.next = 6; break; } return _context.abrupt("return", undefined); case 6: if (!(needBaseCoinFee === PRECISION.IMPRECISE && commissionPriceData)) { _context.next = 11; break; } _context.next = 9; return getPoolInfo$1(0, commissionPriceData.coin.id, extraAxiosOptions); case 9: priceCoinPool = _context.sent; return _context.abrupt("return", getBaseCoinAmountFromPool(priceCoinFee, priceCoinPool)); case 11: if (!(needBaseCoinFee === PRECISION.IMPRECISE && !commissionPriceData)) { _context.next = 13; break; } throw new Error('base coin fee imprecise estimation with omitted price coin is not implemented yet'); case 13: throw new Error('base coin fee precise estimation not implemented yet'); case 14: case "end": return _context.stop(); } }, _callee); }))(); case 22: baseCoinFee = _context2.sent; if (!sameGasAndPriceCoins) { _context2.next = 27; break; } // PRECISE // actual fee may be few pips less than priceCoinFee, assume it's not worth of extra http request fee = priceCoinFee; _context2.next = 37; break; case 27: if (!gasDependsOnBase) { _context2.next = 31; break; } // IMPRECISE fee = baseCoinFee; _context2.next = 37; break; case 31: if (!(needGasCoinFee !== PRECISION.OMIT)) { _context2.next = 37; break; } _context2.next = 34; return estimateFeeDirect(txParams, axiosOptions); case 34: _yield$estimateFeeDir = _context2.sent; commission = _yield$estimateFeeDir.commission; fee = commission; case 37: if (baseDependsOnGas) { baseCoinFee = fee; } return _context2.abrupt("return", { commission: fee, baseCoinCommission: baseCoinFee, priceCoinCommission: priceCoinFee, commissionPriceData: commissionPriceData }); case 39: case "end": return _context2.stop(); } }, _callee2); })); return _estimateFeeCalculate.apply(this, arguments); } } /** * @param {CommissionPriceData} commissionPriceData * @return {boolean} */ function isPriceCoinSameAsBaseCoin(commissionPriceData) { return Number.parseInt(commissionPriceData === null || commissionPriceData === void 0 ? void 0 : commissionPriceData.coin.id, 10) === 0; } /** * @param {number|string} gasCoinId * @param {CommissionPriceData} commissionPriceData * @return {boolean} */ function isGasCoinSameAsPriceCoin(gasCoinId, commissionPriceData) { return Number.parseInt(gasCoinId, 10) === Number.parseInt(commissionPriceData === null || commissionPriceData === void 0 ? void 0 : commissionPriceData.coin.id, 10); } /** * @param {number|string} gasCoinId * @return {boolean} */ function isGasCoinSameAsBaseCoin(gasCoinId) { return Number.parseInt(gasCoinId, 10) === 0; } /** * * @param {number|string} priceCoinAmount * @param {PoolInfo} pool * @return {string|number} */ function getBaseCoinAmountFromPool(priceCoinAmount, pool) { // amount of base coin in pool var reserveBase = new minterjsUtil.Big(pool.amount0); // amount of price coin in pool var reservePrice = new minterjsUtil.Big(pool.amount1); // amount of price coin in pool new minterjsUtil.Big(priceCoinAmount); // @see https://github.com/MinterTeam/minter-go-node/blob/6e44d5691c9df1a9c725d0f52c5921e8523c7f18/coreV2/state/swap/swap.go#L642 // reserveBase - (reservePrice * reserveBase) / (priceCoinAmount * 0.997 + reservePrice) var result = reserveBase.minus(reservePrice.times(reserveBase).div(new minterjsUtil.Big(priceCoinAmount).times(0.997).plus(reservePrice))); // received amount from pool rounds down, spent amount to pool rounds up // round down result = result.round(18, minterjsUtil.BIG_ROUND_DOWN); return result; } /** * @param {TxParams} txParams * @param {boolean} [disableValidation] * @return FeePriceOptions */ function getFeePriceOptionsFromTxParams(txParams, disableValidation) { var _txParams$data; var txType = txParams.type; if (!txType) { throw new Error('Tx `type` not specified'); } var isTickerType = txType === minterjsUtil.TX_TYPE.CREATE_COIN || txType === minterjsUtil.TX_TYPE.CREATE_TOKEN; var coinSymbol = isTickerType ? (_txParams$data = txParams.data) === null || _txParams$data === void 0 ? void 0 : _txParams$data.symbol : undefined; if (isTickerType && !coinSymbol && !disableValidation) { throw new Error('`symbol` not specified for ticker creation tx'); } var deltaItemCount; if (txType === minterjsUtil.TX_TYPE.BUY_SWAP_POOL || txType === minterjsUtil.TX_TYPE.SELL_SWAP_POOL || txType === minterjsUtil.TX_TYPE.SELL_ALL_SWAP_POOL) { var _txParams$data2, _txParams$data2$coins; var coinCount = (_txParams$data2 = txParams.data) === null || _txParams$data2 === void 0 ? void 0 : (_txParams$data2$coins = _txParams$data2.coins) === null || _txParams$data2$coins === void 0 ? void 0 : _txParams$data2$coins.length; if (!coinCount && !disableValidation) { throw new Error('Invalid `coins` field in swap pool tx'); } // count of pools deltaItemCount = coinCount - 1; } if (txType === minterjsUtil.TX_TYPE.MULTISEND) { var _txParams$data3, _txParams$data3$list; // count of recipients deltaItemCount = (_txParams$data3 = txParams.data) === null || _txParams$data3 === void 0 ? void 0 : (_txParams$data3$list = _txParams$data3.list) === null || _txParams$data3$list === void 0 ? void 0 : _txParams$data3$list.length; if (!deltaItemCount && !disableValidation) { throw new Error('Invalid `list` field in multisend tx'); } } return { payload: txParams.payload, coinSymbol: coinSymbol, deltaItemCount: deltaItemCount, fallbackOnInvalidInput: disableValidation }; } exports.FEE_PRECISION_SETTING = FEE_PRECISION_SETTING; exports.default = EstimateTxCommission;