UNPKG

@vechain.energy/gas

Version:

calculate estimated gas usage for transactions

163 lines (162 loc) 7.33 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = feeMarket; const bent_1 = __importDefault(require("bent")); const bignumber_js_1 = __importDefault(require("bignumber.js")); function feeMarket(nodeOrConnex_1) { return __awaiter(this, arguments, void 0, function* (nodeOrConnex, options = {}) { if (typeof nodeOrConnex === "string") { return yield calculateDynamicFee(nodeOrConnex, options); } // For Connex, fall back to legacy calculation return new bignumber_js_1.default(0); }); } function calculateDynamicFee(nodeUrl, options) { return __awaiter(this, void 0, void 0, function* () { // Get current base fee from latest block const baseFee = yield getBaseFeePerGas(nodeUrl); // Calculate priority fee let priorityFee; if (options.maxPriorityFeePerGas !== undefined) { priorityFee = new bignumber_js_1.default(options.maxPriorityFeePerGas); } else { priorityFee = yield calculateOptimalPriorityFee(nodeUrl, baseFee); } const totalFeePerGas = baseFee.plus(priorityFee); // Apply maxFeePerGas cap if specified if (options.maxFeePerGas !== undefined) { const maxFee = new bignumber_js_1.default(options.maxFeePerGas); return bignumber_js_1.default.min(totalFeePerGas, maxFee); } return totalFeePerGas; }); } function getBaseFeePerGas(nodeUrl) { return __awaiter(this, void 0, void 0, function* () { const getNode = (0, bent_1.default)(nodeUrl, 'GET', 'json', 200); try { const response = yield getNode('/blocks/best'); if (response && response.baseFeePerGas) { return new bignumber_js_1.default(response.baseFeePerGas); } // Fallback to legacy base gas price if baseFeePerGas not available return yield getLegacyBaseGasPrice(nodeUrl); } catch (error) { // Fallback to legacy base gas price return yield getLegacyBaseGasPrice(nodeUrl); } }); } function getLegacyBaseGasPrice(nodeUrl) { return __awaiter(this, void 0, void 0, function* () { const postNode = (0, bent_1.default)(nodeUrl, 'POST', 'json', 200); const response = yield postNode('/accounts/*', { clauses: [{ to: '0x0000000000000000000000000000506172616d73', data: '0x8eaa6ac0000000000000000000000000000000000000626173652d6761732d7072696365', value: '0' }] }); if (!Array.isArray(response)) { return new bignumber_js_1.default(0); } const data = response[0].data; // Simple hex to decimal conversion for uint256 const decoded = new bignumber_js_1.default(data.slice(2), 16); return decoded; }); } function calculateOptimalPriorityFee(nodeUrl, baseFee) { return __awaiter(this, void 0, void 0, function* () { try { // Get fee history for recent blocks const feeHistory = yield getFeeHistory(nodeUrl, { blockCount: 10, newestBlock: 'best', rewardPercentiles: [25, 50, 75] }); let percentile75 = new bignumber_js_1.default(0); if (feeHistory.reward && feeHistory.reward.length > 0) { const latestBlockRewards = feeHistory.reward[feeHistory.reward.length - 1]; const equalRewardsOnLastBlock = new Set(latestBlockRewards).size === 3; if (equalRewardsOnLastBlock) { // Use 75th percentile from latest block percentile75 = new bignumber_js_1.default(latestBlockRewards[2], 16); } else { // Calculate average of 75th percentiles across blocks let sum = new bignumber_js_1.default(0); let count = 0; for (const blockRewards of feeHistory.reward) { if (blockRewards.length > 2 && blockRewards[2]) { sum = sum.plus(new bignumber_js_1.default(blockRewards[2], 16)); count++; } } percentile75 = count > 0 ? sum.dividedBy(count) : new bignumber_js_1.default(0); } } else { // Fallback to network-suggested priority fee percentile75 = yield getMaxPriorityFeePerGas(nodeUrl); } // Calculate 4.6% of base fee (HIGH speed threshold) const baseFeeCap = baseFee.times(46).dividedBy(1000); // Use minimum of historical vs. cap values return bignumber_js_1.default.min(baseFeeCap, percentile75); } catch (error) { // Fallback to network-suggested priority fee return yield getMaxPriorityFeePerGas(nodeUrl); } }); } function getFeeHistory(nodeUrl, options) { return __awaiter(this, void 0, void 0, function* () { const getNode = (0, bent_1.default)(nodeUrl, 'GET', 'json', 200); const queryParams = new URLSearchParams({ blockCount: options.blockCount.toString(), newestBlock: options.newestBlock }); if (options.rewardPercentiles) { queryParams.append('rewardPercentiles', options.rewardPercentiles.join(',')); } const response = yield getNode(`/fees/history?${queryParams.toString()}`); if (!response || typeof response !== 'object') { throw new Error('Invalid fee history response'); } return response; }); } function getMaxPriorityFeePerGas(nodeUrl) { return __awaiter(this, void 0, void 0, function* () { const getNode = (0, bent_1.default)(nodeUrl, 'GET', 'json', 200); try { const response = yield getNode('/fees/priority'); if (response && response.maxPriorityFeePerGas) { return new bignumber_js_1.default(response.maxPriorityFeePerGas, 16); } // Fallback to a reasonable default return new bignumber_js_1.default(1000000000); // 1 gwei } catch (error) { // Fallback to a reasonable default return new bignumber_js_1.default(1000000000); // 1 gwei } }); }